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