1 /* 2 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * * Neither the name of Redis nor the names of its contributors may be used 14 * to endorse or promote products derived from this software without 15 * specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "redis.h" 31 #include "sha1.h" 32 #include "rand.h" 33 34 #include <lua.h> 35 #include <lauxlib.h> 36 #include <lualib.h> 37 #include <ctype.h> 38 #include <math.h> 39 40 char *redisProtocolToLuaType_Int(lua_State *lua, char *reply); 41 char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply); 42 char *redisProtocolToLuaType_Status(lua_State *lua, char *reply); 43 char *redisProtocolToLuaType_Error(lua_State *lua, char *reply); 44 char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply); 45 int redis_math_random (lua_State *L); 46 int redis_math_randomseed (lua_State *L); 47 void sha1hex(char *digest, char *script, size_t len); 48 49 /* Take a Redis reply in the Redis protocol format and convert it into a 50 * Lua type. Thanks to this function, and the introduction of not connected 51 * clients, it is trivial to implement the redis() lua function. 52 * 53 * Basically we take the arguments, execute the Redis command in the context 54 * of a non connected client, then take the generated reply and convert it 55 * into a suitable Lua type. With this trick the scripting feature does not 56 * need the introduction of a full Redis internals API. Basically the script 57 * is like a normal client that bypasses all the slow I/O paths. 58 * 59 * Note: in this function we do not do any sanity check as the reply is 60 * generated by Redis directly. This allows us to go faster. 61 * The reply string can be altered during the parsing as it is discarded 62 * after the conversion is completed. 63 * 64 * Errors are returned as a table with a single 'err' field set to the 65 * error string. 66 */ 67 68 char *redisProtocolToLuaType(lua_State *lua, char* reply) { 69 char *p = reply; 70 71 switch(*p) { 72 case ':': 73 p = redisProtocolToLuaType_Int(lua,reply); 74 break; 75 case '$': 76 p = redisProtocolToLuaType_Bulk(lua,reply); 77 break; 78 case '+': 79 p = redisProtocolToLuaType_Status(lua,reply); 80 break; 81 case '-': 82 p = redisProtocolToLuaType_Error(lua,reply); 83 break; 84 case '*': 85 p = redisProtocolToLuaType_MultiBulk(lua,reply); 86 break; 87 } 88 return p; 89 } 90 91 char *redisProtocolToLuaType_Int(lua_State *lua, char *reply) { 92 char *p = strchr(reply+1,'\r'); 93 long long value; 94 95 string2ll(reply+1,p-reply-1,&value); 96 lua_pushnumber(lua,(lua_Number)value); 97 return p+2; 98 } 99 100 char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply) { 101 char *p = strchr(reply+1,'\r'); 102 long long bulklen; 103 104 string2ll(reply+1,p-reply-1,&bulklen); 105 if (bulklen == -1) { 106 lua_pushboolean(lua,0); 107 return p+2; 108 } else { 109 lua_pushlstring(lua,p+2,bulklen); 110 return p+2+bulklen+2; 111 } 112 } 113 114 char *redisProtocolToLuaType_Status(lua_State *lua, char *reply) { 115 char *p = strchr(reply+1,'\r'); 116 117 lua_newtable(lua); 118 lua_pushstring(lua,"ok"); 119 lua_pushlstring(lua,reply+1,p-reply-1); 120 lua_settable(lua,-3); 121 return p+2; 122 } 123 124 char *redisProtocolToLuaType_Error(lua_State *lua, char *reply) { 125 char *p = strchr(reply+1,'\r'); 126 127 lua_newtable(lua); 128 lua_pushstring(lua,"err"); 129 lua_pushlstring(lua,reply+1,p-reply-1); 130 lua_settable(lua,-3); 131 return p+2; 132 } 133 134 char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply) { 135 char *p = strchr(reply+1,'\r'); 136 long long mbulklen; 137 int j = 0; 138 139 string2ll(reply+1,p-reply-1,&mbulklen); 140 p += 2; 141 if (mbulklen == -1) { 142 lua_pushboolean(lua,0); 143 return p; 144 } 145 lua_newtable(lua); 146 for (j = 0; j < mbulklen; j++) { 147 lua_pushnumber(lua,j+1); 148 p = redisProtocolToLuaType(lua,p); 149 lua_settable(lua,-3); 150 } 151 return p; 152 } 153 154 void luaPushError(lua_State *lua, char *error) { 155 lua_newtable(lua); 156 lua_pushstring(lua,"err"); 157 lua_pushstring(lua, error); 158 lua_settable(lua,-3); 159 } 160 161 /* Sort the array currently in the stack. We do this to make the output 162 * of commands like KEYS or SMEMBERS something deterministic when called 163 * from Lua (to play well with AOf/replication). 164 * 165 * The array is sorted using table.sort itself, and assuming all the 166 * list elements are strings. */ 167 void luaSortArray(lua_State *lua) { 168 /* Initial Stack: array */ 169 lua_getglobal(lua,"table"); 170 lua_pushstring(lua,"sort"); 171 lua_gettable(lua,-2); /* Stack: array, table, table.sort */ 172 lua_pushvalue(lua,-3); /* Stack: array, table, table.sort, array */ 173 if (lua_pcall(lua,1,0,0)) { 174 /* Stack: array, table, error */ 175 176 /* We are not interested in the error, we assume that the problem is 177 * that there are 'false' elements inside the array, so we try 178 * again with a slower function but able to handle this case, that 179 * is: table.sort(table, __redis__compare_helper) */ 180 lua_pop(lua,1); /* Stack: array, table */ 181 lua_pushstring(lua,"sort"); /* Stack: array, table, sort */ 182 lua_gettable(lua,-2); /* Stack: array, table, table.sort */ 183 lua_pushvalue(lua,-3); /* Stack: array, table, table.sort, array */ 184 lua_getglobal(lua,"__redis__compare_helper"); 185 /* Stack: array, table, table.sort, array, __redis__compare_helper */ 186 lua_call(lua,2,0); 187 } 188 /* Stack: array (sorted), table */ 189 lua_pop(lua,1); /* Stack: array (sorted) */ 190 } 191 192 int luaRedisGenericCommand(lua_State *lua, int raise_error) { 193 int j, argc = lua_gettop(lua); 194 struct redisCommand *cmd; 195 robj **argv; 196 redisClient *c = server.lua_client; 197 sds reply; 198 199 /* Require at least one argument */ 200 if (argc == 0) { 201 luaPushError(lua, 202 "Please specify at least one argument for redis.call()"); 203 return 1; 204 } 205 206 /* Build the arguments vector */ 207 argv = zmalloc(sizeof(robj*)*argc); 208 for (j = 0; j < argc; j++) { 209 if (!lua_isstring(lua,j+1)) break; 210 argv[j] = createStringObject((char*)lua_tostring(lua,j+1), 211 lua_strlen(lua,j+1)); 212 } 213 214 /* Check if one of the arguments passed by the Lua script 215 * is not a string or an integer (lua_isstring() return true for 216 * integers as well). */ 217 if (j != argc) { 218 j--; 219 while (j >= 0) { 220 decrRefCount(argv[j]); 221 j--; 222 } 223 zfree(argv); 224 luaPushError(lua, 225 "Lua redis() command arguments must be strings or integers"); 226 return 1; 227 } 228 229 /* Setup our fake client for command execution */ 230 c->argv = argv; 231 c->argc = argc; 232 233 /* Command lookup */ 234 cmd = lookupCommand(argv[0]->ptr); 235 if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) || 236 (argc < -cmd->arity))) 237 { 238 if (cmd) 239 luaPushError(lua, 240 "Wrong number of args calling Redis command From Lua script"); 241 else 242 luaPushError(lua,"Unknown Redis command called from Lua script"); 243 goto cleanup; 244 } 245 246 /* There are commands that are not allowed inside scripts. */ 247 if (cmd->flags & REDIS_CMD_NOSCRIPT) { 248 luaPushError(lua, "This Redis command is not allowed from scripts"); 249 goto cleanup; 250 } 251 252 /* Write commands are forbidden against read-only slaves, or if a 253 * command marked as non-deterministic was already called in the context 254 * of this script. */ 255 if (cmd->flags & REDIS_CMD_WRITE) { 256 if (server.lua_random_dirty) { 257 luaPushError(lua, 258 "Write commands not allowed after non deterministic commands"); 259 goto cleanup; 260 } else if (server.masterhost && server.repl_slave_ro && 261 !(server.lua_caller->flags & REDIS_MASTER)) 262 { 263 luaPushError(lua, shared.roslaveerr->ptr); 264 goto cleanup; 265 } else if (server.stop_writes_on_bgsave_err && 266 server.saveparamslen > 0 && 267 server.lastbgsave_status == REDIS_ERR) 268 { 269 luaPushError(lua, shared.bgsaveerr->ptr); 270 goto cleanup; 271 } 272 } 273 274 /* If we reached the memory limit configured via maxmemory, commands that 275 * could enlarge the memory usage are not allowed, but only if this is the 276 * first write in the context of this script, otherwise we can't stop 277 * in the middle. */ 278 if (server.maxmemory && server.lua_write_dirty == 0 && 279 (cmd->flags & REDIS_CMD_DENYOOM)) 280 { 281 if (freeMemoryIfNeeded() == REDIS_ERR) { 282 luaPushError(lua, shared.oomerr->ptr); 283 goto cleanup; 284 } 285 } 286 287 if (cmd->flags & REDIS_CMD_RANDOM) server.lua_random_dirty = 1; 288 if (cmd->flags & REDIS_CMD_WRITE) server.lua_write_dirty = 1; 289 290 /* Run the command */ 291 c->cmd = cmd; 292 call(c,REDIS_CALL_SLOWLOG | REDIS_CALL_STATS); 293 294 /* Convert the result of the Redis command into a suitable Lua type. 295 * The first thing we need is to create a single string from the client 296 * output buffers. */ 297 reply = sdsempty(); 298 if (c->bufpos) { 299 reply = sdscatlen(reply,c->buf,c->bufpos); 300 c->bufpos = 0; 301 } 302 while(listLength(c->reply)) { 303 robj *o = listNodeValue(listFirst(c->reply)); 304 305 reply = sdscatlen(reply,o->ptr,sdslen(o->ptr)); 306 listDelNode(c->reply,listFirst(c->reply)); 307 } 308 if (raise_error && reply[0] != '-') raise_error = 0; 309 redisProtocolToLuaType(lua,reply); 310 /* Sort the output array if needed, assuming it is a non-null multi bulk 311 * reply as expected. */ 312 if ((cmd->flags & REDIS_CMD_SORT_FOR_SCRIPT) && 313 (reply[0] == '*' && reply[1] != '-')) { 314 luaSortArray(lua); 315 } 316 sdsfree(reply); 317 c->reply_bytes = 0; 318 319 cleanup: 320 /* Clean up. Command code may have changed argv/argc so we use the 321 * argv/argc of the client instead of the local variables. */ 322 for (j = 0; j < c->argc; j++) 323 decrRefCount(c->argv[j]); 324 zfree(c->argv); 325 326 if (raise_error) { 327 /* If we are here we should have an error in the stack, in the 328 * form of a table with an "err" field. Extract the string to 329 * return the plain error. */ 330 lua_pushstring(lua,"err"); 331 lua_gettable(lua,-2); 332 return lua_error(lua); 333 } 334 return 1; 335 } 336 337 int luaRedisCallCommand(lua_State *lua) { 338 return luaRedisGenericCommand(lua,1); 339 } 340 341 int luaRedisPCallCommand(lua_State *lua) { 342 return luaRedisGenericCommand(lua,0); 343 } 344 345 /* This adds redis.sha1hex(string) to Lua scripts using the same hashing 346 * function used for sha1ing lua scripts. */ 347 int luaRedisSha1hexCommand(lua_State *lua) { 348 int argc = lua_gettop(lua); 349 char digest[41]; 350 size_t len; 351 char *s; 352 353 if (argc != 1) { 354 luaPushError(lua, "wrong number of arguments"); 355 return 1; 356 } 357 358 s = (char*)lua_tolstring(lua,1,&len); 359 sha1hex(digest,s,len); 360 lua_pushstring(lua,digest); 361 return 1; 362 } 363 364 /* Returns a table with a single field 'field' set to the string value 365 * passed as argument. This helper function is handy when returning 366 * a Redis Protocol error or status reply from Lua: 367 * 368 * return redis.error_reply("ERR Some Error") 369 * return redis.status_reply("ERR Some Error") 370 */ 371 int luaRedisReturnSingleFieldTable(lua_State *lua, char *field) { 372 if (lua_gettop(lua) != 1 || lua_type(lua,-1) != LUA_TSTRING) { 373 luaPushError(lua, "wrong number or type of arguments"); 374 return 1; 375 } 376 377 lua_newtable(lua); 378 lua_pushstring(lua, field); 379 lua_pushvalue(lua, -3); 380 lua_settable(lua, -3); 381 return 1; 382 } 383 384 int luaRedisErrorReplyCommand(lua_State *lua) { 385 return luaRedisReturnSingleFieldTable(lua,"err"); 386 } 387 388 int luaRedisStatusReplyCommand(lua_State *lua) { 389 return luaRedisReturnSingleFieldTable(lua,"ok"); 390 } 391 392 int luaLogCommand(lua_State *lua) { 393 int j, argc = lua_gettop(lua); 394 int level; 395 sds log; 396 397 if (argc < 2) { 398 luaPushError(lua, "redis.log() requires two arguments or more."); 399 return 1; 400 } else if (!lua_isnumber(lua,-argc)) { 401 luaPushError(lua, "First argument must be a number (log level)."); 402 return 1; 403 } 404 level = lua_tonumber(lua,-argc); 405 if (level < REDIS_DEBUG || level > REDIS_WARNING) { 406 luaPushError(lua, "Invalid debug level."); 407 return 1; 408 } 409 410 /* Glue together all the arguments */ 411 log = sdsempty(); 412 for (j = 1; j < argc; j++) { 413 size_t len; 414 char *s; 415 416 s = (char*)lua_tolstring(lua,(-argc)+j,&len); 417 if (s) { 418 if (j != 1) log = sdscatlen(log," ",1); 419 log = sdscatlen(log,s,len); 420 } 421 } 422 redisLogRaw(level,log); 423 sdsfree(log); 424 return 0; 425 } 426 427 void luaMaskCountHook(lua_State *lua, lua_Debug *ar) { 428 long long elapsed; 429 REDIS_NOTUSED(ar); 430 REDIS_NOTUSED(lua); 431 432 elapsed = (ustime()/1000) - server.lua_time_start; 433 if (elapsed >= server.lua_time_limit && server.lua_timedout == 0) { 434 redisLog(REDIS_WARNING,"Lua slow script detected: still in execution after %lld milliseconds. You can try killing the script using the SCRIPT KILL command.",elapsed); 435 server.lua_timedout = 1; 436 /* Once the script timeouts we reenter the event loop to permit others 437 * to call SCRIPT KILL or SHUTDOWN NOSAVE if needed. For this reason 438 * we need to mask the client executing the script from the event loop. 439 * If we don't do that the client may disconnect and could no longer be 440 * here when the EVAL command will return. */ 441 aeDeleteFileEvent(server.el, server.lua_caller->fd, AE_READABLE); 442 } 443 if (server.lua_timedout) 444 aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT); 445 if (server.lua_kill) { 446 redisLog(REDIS_WARNING,"Lua script killed by user with SCRIPT KILL."); 447 lua_pushstring(lua,"Script killed by user with SCRIPT KILL..."); 448 lua_error(lua); 449 } 450 } 451 452 void luaLoadLib(lua_State *lua, const char *libname, lua_CFunction luafunc) { 453 lua_pushcfunction(lua, luafunc); 454 lua_pushstring(lua, libname); 455 lua_call(lua, 1, 0); 456 } 457 458 LUALIB_API int (luaopen_cjson) (lua_State *L); 459 LUALIB_API int (luaopen_struct) (lua_State *L); 460 LUALIB_API int (luaopen_cmsgpack) (lua_State *L); 461 462 void luaLoadLibraries(lua_State *lua) { 463 luaLoadLib(lua, "", luaopen_base); 464 luaLoadLib(lua, LUA_TABLIBNAME, luaopen_table); 465 luaLoadLib(lua, LUA_STRLIBNAME, luaopen_string); 466 luaLoadLib(lua, LUA_MATHLIBNAME, luaopen_math); 467 luaLoadLib(lua, LUA_DBLIBNAME, luaopen_debug); 468 luaLoadLib(lua, "cjson", luaopen_cjson); 469 luaLoadLib(lua, "struct", luaopen_struct); 470 luaLoadLib(lua, "cmsgpack", luaopen_cmsgpack); 471 472 #if 0 /* Stuff that we don't load currently, for sandboxing concerns. */ 473 luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package); 474 luaLoadLib(lua, LUA_OSLIBNAME, luaopen_os); 475 #endif 476 } 477 478 /* Remove a functions that we don't want to expose to the Redis scripting 479 * environment. */ 480 void luaRemoveUnsupportedFunctions(lua_State *lua) { 481 lua_pushnil(lua); 482 lua_setglobal(lua,"loadfile"); 483 } 484 485 /* This function installs metamethods in the global table _G that prevent 486 * the creation of globals accidentally. 487 * 488 * It should be the last to be called in the scripting engine initialization 489 * sequence, because it may interact with creation of globals. */ 490 void scriptingEnableGlobalsProtection(lua_State *lua) { 491 char *s[32]; 492 sds code = sdsempty(); 493 int j = 0; 494 495 /* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html. 496 * Modified to be adapted to Redis. */ 497 s[j++]="local mt = {}\n"; 498 s[j++]="setmetatable(_G, mt)\n"; 499 s[j++]="mt.__newindex = function (t, n, v)\n"; 500 s[j++]=" if debug.getinfo(2) then\n"; 501 s[j++]=" local w = debug.getinfo(2, \"S\").what\n"; 502 s[j++]=" if w ~= \"main\" and w ~= \"C\" then\n"; 503 s[j++]=" error(\"Script attempted to create global variable '\"..tostring(n)..\"'\", 2)\n"; 504 s[j++]=" end\n"; 505 s[j++]=" end\n"; 506 s[j++]=" rawset(t, n, v)\n"; 507 s[j++]="end\n"; 508 s[j++]="mt.__index = function (t, n)\n"; 509 s[j++]=" if debug.getinfo(2) and debug.getinfo(2, \"S\").what ~= \"C\" then\n"; 510 s[j++]=" error(\"Script attempted to access unexisting global variable '\"..tostring(n)..\"'\", 2)\n"; 511 s[j++]=" end\n"; 512 s[j++]=" return rawget(t, n)\n"; 513 s[j++]="end\n"; 514 s[j++]=NULL; 515 516 for (j = 0; s[j] != NULL; j++) code = sdscatlen(code,s[j],strlen(s[j])); 517 luaL_loadbuffer(lua,code,sdslen(code),"@enable_strict_lua"); 518 lua_pcall(lua,0,0,0); 519 sdsfree(code); 520 } 521 522 /* Initialize the scripting environment. 523 * It is possible to call this function to reset the scripting environment 524 * assuming that we call scriptingRelease() before. 525 * See scriptingReset() for more information. */ 526 void scriptingInit(void) { 527 lua_State *lua = lua_open(); 528 529 luaLoadLibraries(lua); 530 luaRemoveUnsupportedFunctions(lua); 531 532 /* Initialize a dictionary we use to map SHAs to scripts. 533 * This is useful for replication, as we need to replicate EVALSHA 534 * as EVAL, so we need to remember the associated script. */ 535 server.lua_scripts = dictCreate(&shaScriptObjectDictType,NULL); 536 537 /* Register the redis commands table and fields */ 538 lua_newtable(lua); 539 540 /* redis.call */ 541 lua_pushstring(lua,"call"); 542 lua_pushcfunction(lua,luaRedisCallCommand); 543 lua_settable(lua,-3); 544 545 /* redis.pcall */ 546 lua_pushstring(lua,"pcall"); 547 lua_pushcfunction(lua,luaRedisPCallCommand); 548 lua_settable(lua,-3); 549 550 /* redis.log and log levels. */ 551 lua_pushstring(lua,"log"); 552 lua_pushcfunction(lua,luaLogCommand); 553 lua_settable(lua,-3); 554 555 lua_pushstring(lua,"LOG_DEBUG"); 556 lua_pushnumber(lua,REDIS_DEBUG); 557 lua_settable(lua,-3); 558 559 lua_pushstring(lua,"LOG_VERBOSE"); 560 lua_pushnumber(lua,REDIS_VERBOSE); 561 lua_settable(lua,-3); 562 563 lua_pushstring(lua,"LOG_NOTICE"); 564 lua_pushnumber(lua,REDIS_NOTICE); 565 lua_settable(lua,-3); 566 567 lua_pushstring(lua,"LOG_WARNING"); 568 lua_pushnumber(lua,REDIS_WARNING); 569 lua_settable(lua,-3); 570 571 /* redis.sha1hex */ 572 lua_pushstring(lua, "sha1hex"); 573 lua_pushcfunction(lua, luaRedisSha1hexCommand); 574 lua_settable(lua, -3); 575 576 /* redis.error_reply and redis.status_reply */ 577 lua_pushstring(lua, "error_reply"); 578 lua_pushcfunction(lua, luaRedisErrorReplyCommand); 579 lua_settable(lua, -3); 580 lua_pushstring(lua, "status_reply"); 581 lua_pushcfunction(lua, luaRedisStatusReplyCommand); 582 lua_settable(lua, -3); 583 584 /* Finally set the table as 'redis' global var. */ 585 lua_setglobal(lua,"redis"); 586 587 /* Replace math.random and math.randomseed with our implementations. */ 588 lua_getglobal(lua,"math"); 589 590 lua_pushstring(lua,"random"); 591 lua_pushcfunction(lua,redis_math_random); 592 lua_settable(lua,-3); 593 594 lua_pushstring(lua,"randomseed"); 595 lua_pushcfunction(lua,redis_math_randomseed); 596 lua_settable(lua,-3); 597 598 lua_setglobal(lua,"math"); 599 600 /* Add a helper function that we use to sort the multi bulk output of non 601 * deterministic commands, when containing 'false' elements. */ 602 { 603 char *compare_func = "function __redis__compare_helper(a,b)\n" 604 " if a == false then a = '' end\n" 605 " if b == false then b = '' end\n" 606 " return a<b\n" 607 "end\n"; 608 luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def"); 609 lua_pcall(lua,0,0,0); 610 } 611 612 /* Create the (non connected) client that we use to execute Redis commands 613 * inside the Lua interpreter. 614 * Note: there is no need to create it again when this function is called 615 * by scriptingReset(). */ 616 if (server.lua_client == NULL) { 617 server.lua_client = createClient(-1); 618 server.lua_client->flags |= REDIS_LUA_CLIENT; 619 } 620 621 /* Lua beginners ofter don't use "local", this is likely to introduce 622 * subtle bugs in their code. To prevent problems we protect accesses 623 * to global variables. */ 624 scriptingEnableGlobalsProtection(lua); 625 626 server.lua = lua; 627 } 628 629 /* Release resources related to Lua scripting. 630 * This function is used in order to reset the scripting environment. */ 631 void scriptingRelease(void) { 632 dictRelease(server.lua_scripts); 633 lua_close(server.lua); 634 } 635 636 void scriptingReset(void) { 637 scriptingRelease(); 638 scriptingInit(); 639 } 640 641 /* Perform the SHA1 of the input string. We use this both for hashing script 642 * bodies in order to obtain the Lua function name, and in the implementation 643 * of redis.sha1(). 644 * 645 * 'digest' should point to a 41 bytes buffer: 40 for SHA1 converted into an 646 * hexadecimal number, plus 1 byte for null term. */ 647 void sha1hex(char *digest, char *script, size_t len) { 648 SHA1_CTX ctx; 649 unsigned char hash[20]; 650 char *cset = "0123456789abcdef"; 651 int j; 652 653 SHA1Init(&ctx); 654 SHA1Update(&ctx,(unsigned char*)script,len); 655 SHA1Final(hash,&ctx); 656 657 for (j = 0; j < 20; j++) { 658 digest[j*2] = cset[((hash[j]&0xF0)>>4)]; 659 digest[j*2+1] = cset[(hash[j]&0xF)]; 660 } 661 digest[40] = '\0'; 662 } 663 664 void luaReplyToRedisReply(redisClient *c, lua_State *lua) { 665 int t = lua_type(lua,-1); 666 667 switch(t) { 668 case LUA_TSTRING: 669 addReplyBulkCBuffer(c,(char*)lua_tostring(lua,-1),lua_strlen(lua,-1)); 670 break; 671 case LUA_TBOOLEAN: 672 addReply(c,lua_toboolean(lua,-1) ? shared.cone : shared.nullbulk); 673 break; 674 case LUA_TNUMBER: 675 addReplyLongLong(c,(long long)lua_tonumber(lua,-1)); 676 break; 677 case LUA_TTABLE: 678 /* We need to check if it is an array, an error, or a status reply. 679 * Error are returned as a single element table with 'err' field. 680 * Status replies are returned as single element table with 'ok' field */ 681 lua_pushstring(lua,"err"); 682 lua_gettable(lua,-2); 683 t = lua_type(lua,-1); 684 if (t == LUA_TSTRING) { 685 sds err = sdsnew(lua_tostring(lua,-1)); 686 sdsmapchars(err,"\r\n"," ",2); 687 addReplySds(c,sdscatprintf(sdsempty(),"-%s\r\n",err)); 688 sdsfree(err); 689 lua_pop(lua,2); 690 return; 691 } 692 693 lua_pop(lua,1); 694 lua_pushstring(lua,"ok"); 695 lua_gettable(lua,-2); 696 t = lua_type(lua,-1); 697 if (t == LUA_TSTRING) { 698 sds ok = sdsnew(lua_tostring(lua,-1)); 699 sdsmapchars(ok,"\r\n"," ",2); 700 addReplySds(c,sdscatprintf(sdsempty(),"+%s\r\n",ok)); 701 sdsfree(ok); 702 lua_pop(lua,1); 703 } else { 704 void *replylen = addDeferredMultiBulkLength(c); 705 int j = 1, mbulklen = 0; 706 707 lua_pop(lua,1); /* Discard the 'ok' field value we popped */ 708 while(1) { 709 lua_pushnumber(lua,j++); 710 lua_gettable(lua,-2); 711 t = lua_type(lua,-1); 712 if (t == LUA_TNIL) { 713 lua_pop(lua,1); 714 break; 715 } 716 luaReplyToRedisReply(c, lua); 717 mbulklen++; 718 } 719 setDeferredMultiBulkLength(c,replylen,mbulklen); 720 } 721 break; 722 default: 723 addReply(c,shared.nullbulk); 724 } 725 lua_pop(lua,1); 726 } 727 728 /* Set an array of Redis String Objects as a Lua array (table) stored into a 729 * global variable. */ 730 void luaSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec) { 731 int j; 732 733 lua_newtable(lua); 734 for (j = 0; j < elec; j++) { 735 lua_pushlstring(lua,(char*)elev[j]->ptr,sdslen(elev[j]->ptr)); 736 lua_rawseti(lua,-2,j+1); 737 } 738 lua_setglobal(lua,var); 739 } 740 741 /* Define a lua function with the specified function name and body. 742 * The function name musts be a 2 characters long string, since all the 743 * functions we defined in the Lua context are in the form: 744 * 745 * f_<hex sha1 sum> 746 * 747 * On success REDIS_OK is returned, and nothing is left on the Lua stack. 748 * On error REDIS_ERR is returned and an appropriate error is set in the 749 * client context. */ 750 int luaCreateFunction(redisClient *c, lua_State *lua, char *funcname, robj *body) { 751 sds funcdef = sdsempty(); 752 753 funcdef = sdscat(funcdef,"function "); 754 funcdef = sdscatlen(funcdef,funcname,42); 755 funcdef = sdscatlen(funcdef,"() ",3); 756 funcdef = sdscatlen(funcdef,body->ptr,sdslen(body->ptr)); 757 funcdef = sdscatlen(funcdef," end",4); 758 759 if (luaL_loadbuffer(lua,funcdef,sdslen(funcdef),"@user_script")) { 760 addReplyErrorFormat(c,"Error compiling script (new function): %s\n", 761 lua_tostring(lua,-1)); 762 lua_pop(lua,1); 763 sdsfree(funcdef); 764 return REDIS_ERR; 765 } 766 sdsfree(funcdef); 767 if (lua_pcall(lua,0,0,0)) { 768 addReplyErrorFormat(c,"Error running script (new function): %s\n", 769 lua_tostring(lua,-1)); 770 lua_pop(lua,1); 771 return REDIS_ERR; 772 } 773 774 /* We also save a SHA1 -> Original script map in a dictionary 775 * so that we can replicate / write in the AOF all the 776 * EVALSHA commands as EVAL using the original script. */ 777 { 778 int retval = dictAdd(server.lua_scripts, 779 sdsnewlen(funcname+2,40),body); 780 redisAssertWithInfo(c,NULL,retval == DICT_OK); 781 incrRefCount(body); 782 } 783 return REDIS_OK; 784 } 785 786 void evalGenericCommand(redisClient *c, int evalsha) { 787 lua_State *lua = server.lua; 788 char funcname[43]; 789 long long numkeys; 790 int delhook = 0, err; 791 792 /* We want the same PRNG sequence at every call so that our PRNG is 793 * not affected by external state. */ 794 redisSrand48(0); 795 796 /* We set this flag to zero to remember that so far no random command 797 * was called. This way we can allow the user to call commands like 798 * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command 799 * is called (otherwise the replication and AOF would end with non 800 * deterministic sequences). 801 * 802 * Thanks to this flag we'll raise an error every time a write command 803 * is called after a random command was used. */ 804 server.lua_random_dirty = 0; 805 server.lua_write_dirty = 0; 806 807 /* Get the number of arguments that are keys */ 808 if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != REDIS_OK) 809 return; 810 if (numkeys > (c->argc - 3)) { 811 addReplyError(c,"Number of keys can't be greater than number of args"); 812 return; 813 } 814 815 /* We obtain the script SHA1, then check if this function is already 816 * defined into the Lua state */ 817 funcname[0] = 'f'; 818 funcname[1] = '_'; 819 if (!evalsha) { 820 /* Hash the code if this is an EVAL call */ 821 sha1hex(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr)); 822 } else { 823 /* We already have the SHA if it is a EVALSHA */ 824 int j; 825 char *sha = c->argv[1]->ptr; 826 827 for (j = 0; j < 40; j++) 828 funcname[j+2] = tolower(sha[j]); 829 funcname[42] = '\0'; 830 } 831 832 /* Try to lookup the Lua function */ 833 lua_getglobal(lua, funcname); 834 if (lua_isnil(lua,1)) { 835 lua_pop(lua,1); /* remove the nil from the stack */ 836 /* Function not defined... let's define it if we have the 837 * body of the function. If this is an EVALSHA call we can just 838 * return an error. */ 839 if (evalsha) { 840 addReply(c, shared.noscripterr); 841 return; 842 } 843 if (luaCreateFunction(c,lua,funcname,c->argv[1]) == REDIS_ERR) return; 844 /* Now the following is guaranteed to return non nil */ 845 lua_getglobal(lua, funcname); 846 redisAssert(!lua_isnil(lua,1)); 847 } 848 849 /* Populate the argv and keys table accordingly to the arguments that 850 * EVAL received. */ 851 luaSetGlobalArray(lua,"KEYS",c->argv+3,numkeys); 852 luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argc-3-numkeys); 853 854 /* Select the right DB in the context of the Lua client */ 855 selectDb(server.lua_client,c->db->id); 856 857 /* Set an hook in order to be able to stop the script execution if it 858 * is running for too much time. 859 * We set the hook only if the time limit is enabled as the hook will 860 * make the Lua script execution slower. */ 861 server.lua_caller = c; 862 server.lua_time_start = ustime()/1000; 863 server.lua_kill = 0; 864 if (server.lua_time_limit > 0 && server.masterhost == NULL) { 865 lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000); 866 delhook = 1; 867 } 868 869 /* At this point whatever this script was never seen before or if it was 870 * already defined, we can call it. We have zero arguments and expect 871 * a single return value. */ 872 err = lua_pcall(lua,0,1,0); 873 874 /* Perform some cleanup that we need to do both on error and success. */ 875 if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */ 876 if (server.lua_timedout) { 877 server.lua_timedout = 0; 878 /* Restore the readable handler that was unregistered when the 879 * script timeout was detected. */ 880 aeCreateFileEvent(server.el,c->fd,AE_READABLE, 881 readQueryFromClient,c); 882 } 883 server.lua_caller = NULL; 884 selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */ 885 lua_gc(lua,LUA_GCSTEP,1); 886 887 if (err) { 888 addReplyErrorFormat(c,"Error running script (call to %s): %s\n", 889 funcname, lua_tostring(lua,-1)); 890 lua_pop(lua,1); /* Consume the Lua reply. */ 891 } else { 892 /* On success convert the Lua return value into Redis protocol, and 893 * send it to * the client. */ 894 luaReplyToRedisReply(c,lua); 895 } 896 897 /* If we have slaves attached we want to replicate this command as 898 * EVAL instead of EVALSHA. We do this also in the AOF as currently there 899 * is no easy way to propagate a command in a different way in the AOF 900 * and in the replication link. 901 * 902 * IMPROVEMENT POSSIBLE: 903 * 1) Replicate this command as EVALSHA in the AOF. 904 * 2) Remember what slave already received a given script, and replicate 905 * the EVALSHA against this slaves when possible. 906 */ 907 if (evalsha) { 908 robj *script = dictFetchValue(server.lua_scripts,c->argv[1]->ptr); 909 910 redisAssertWithInfo(c,NULL,script != NULL); 911 rewriteClientCommandArgument(c,0, 912 resetRefCount(createStringObject("EVAL",4))); 913 rewriteClientCommandArgument(c,1,script); 914 } 915 } 916 917 void evalCommand(redisClient *c) { 918 evalGenericCommand(c,0); 919 } 920 921 void evalShaCommand(redisClient *c) { 922 if (sdslen(c->argv[1]->ptr) != 40) { 923 /* We know that a match is not possible if the provided SHA is 924 * not the right length. So we return an error ASAP, this way 925 * evalGenericCommand() can be implemented without string length 926 * sanity check */ 927 addReply(c, shared.noscripterr); 928 return; 929 } 930 evalGenericCommand(c,1); 931 } 932 933 /* We replace math.random() with our implementation that is not affected 934 * by specific libc random() implementations and will output the same sequence 935 * (for the same seed) in every arch. */ 936 937 /* The following implementation is the one shipped with Lua itself but with 938 * rand() replaced by redisLrand48(). */ 939 int redis_math_random (lua_State *L) { 940 /* the `%' avoids the (rare) case of r==1, and is needed also because on 941 some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ 942 lua_Number r = (lua_Number)(redisLrand48()%REDIS_LRAND48_MAX) / 943 (lua_Number)REDIS_LRAND48_MAX; 944 switch (lua_gettop(L)) { /* check number of arguments */ 945 case 0: { /* no arguments */ 946 lua_pushnumber(L, r); /* Number between 0 and 1 */ 947 break; 948 } 949 case 1: { /* only upper limit */ 950 int u = luaL_checkint(L, 1); 951 luaL_argcheck(L, 1<=u, 1, "interval is empty"); 952 lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ 953 break; 954 } 955 case 2: { /* lower and upper limits */ 956 int l = luaL_checkint(L, 1); 957 int u = luaL_checkint(L, 2); 958 luaL_argcheck(L, l<=u, 2, "interval is empty"); 959 lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ 960 break; 961 } 962 default: return luaL_error(L, "wrong number of arguments"); 963 } 964 return 1; 965 } 966 967 int redis_math_randomseed (lua_State *L) { 968 redisSrand48(luaL_checkint(L, 1)); 969 return 0; 970 } 971 972 /* --------------------------------------------------------------------------- 973 * SCRIPT command for script environment introspection and control 974 * ------------------------------------------------------------------------- */ 975 976 void scriptCommand(redisClient *c) { 977 if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"flush")) { 978 scriptingReset(); 979 addReply(c,shared.ok); 980 server.dirty++; /* Replicating this command is a good idea. */ 981 } else if (c->argc >= 2 && !strcasecmp(c->argv[1]->ptr,"exists")) { 982 int j; 983 984 addReplyMultiBulkLen(c, c->argc-2); 985 for (j = 2; j < c->argc; j++) { 986 if (dictFind(server.lua_scripts,c->argv[j]->ptr)) 987 addReply(c,shared.cone); 988 else 989 addReply(c,shared.czero); 990 } 991 } else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,"load")) { 992 char funcname[43]; 993 sds sha; 994 995 funcname[0] = 'f'; 996 funcname[1] = '_'; 997 sha1hex(funcname+2,c->argv[2]->ptr,sdslen(c->argv[2]->ptr)); 998 sha = sdsnewlen(funcname+2,40); 999 if (dictFind(server.lua_scripts,sha) == NULL) { 1000 if (luaCreateFunction(c,server.lua,funcname,c->argv[2]) 1001 == REDIS_ERR) { 1002 sdsfree(sha); 1003 return; 1004 } 1005 } 1006 addReplyBulkCBuffer(c,funcname+2,40); 1007 sdsfree(sha); 1008 } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"kill")) { 1009 if (server.lua_caller == NULL) { 1010 addReplySds(c,sdsnew("-NOTBUSY No scripts in execution right now.\r\n")); 1011 } else if (server.lua_write_dirty) { 1012 addReplySds(c,sdsnew("-UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in an hard way using the SHUTDOWN NOSAVE command.\r\n")); 1013 } else { 1014 server.lua_kill = 1; 1015 addReply(c,shared.ok); 1016 } 1017 } else { 1018 addReplyError(c, "Unknown SCRIPT subcommand or wrong # of args."); 1019 } 1020 } 1021