Commit 4faddf18 authored by Oran Agra's avatar Oran Agra
Browse files

Build TLS as a loadable module

* Support BUILD_TLS=module to be loaded as a module via config file or
  command line. e.g. redis-server --loadmodule redis-tls.so
* Updates to redismodule.h to allow it to be used side by side with
  server.h by defining REDISMODULE_CORE_MODULE
* Changes to server.h, redismodule.h and module.c to avoid repeated
  type declarations (gcc 4.8 doesn't like these)
* Add a mechanism for non-ABI neutral modules (ones who include
  server.h) to refuse loading if they detect not being built together with
  redis (release.c)
* Fix wrong signature of RedisModuleDefragFunc, this could break
  compilation of a module, but not the ABI
* Move initialization of listeners in server.c to be after loading
  the modules
* Config TLS after initialization of listeners
* Init cluster after initialization of listeners
* Add TLS module to CI
* Fix a test suite race conditions:
  Now that the listeners are initialized later, it's not sufficient to
  wait for the PID message in the log, we need to wa...
parent 89e11486
...@@ -24,7 +24,8 @@ jobs: ...@@ -24,7 +24,8 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: make - name: make
run: make SANITIZER=address REDIS_CFLAGS='-Werror' # build with TLS module just for compilation coverage
run: make SANITIZER=address REDIS_CFLAGS='-Werror' BUILD_TLS=module
- name: testprep - name: testprep
run: sudo apt-get install tcl8.6 tclx -y run: sudo apt-get install tcl8.6 tclx -y
- name: test - name: test
......
...@@ -539,7 +539,7 @@ jobs: ...@@ -539,7 +539,7 @@ jobs:
run: | run: |
yum -y install centos-release-scl epel-release yum -y install centos-release-scl epel-release
yum -y install devtoolset-7 openssl-devel openssl yum -y install devtoolset-7 openssl-devel openssl
scl enable devtoolset-7 "make BUILD_TLS=yes REDIS_CFLAGS='-Werror'" scl enable devtoolset-7 "make BUILD_TLS=module REDIS_CFLAGS='-Werror'"
- name: testprep - name: testprep
run: | run: |
yum -y install tcl tcltls tclx yum -y install tcl tcltls tclx
...@@ -547,19 +547,19 @@ jobs: ...@@ -547,19 +547,19 @@ jobs:
- name: test - name: test
if: true && !contains(github.event.inputs.skiptests, 'redis') if: true && !contains(github.event.inputs.skiptests, 'redis')
run: | run: |
./runtest --accurate --verbose --dump-logs --tls --dump-logs ${{github.event.inputs.test_args}} ./runtest --accurate --verbose --dump-logs --tls-module --dump-logs ${{github.event.inputs.test_args}}
- name: module api test - name: module api test
if: true && !contains(github.event.inputs.skiptests, 'modules') if: true && !contains(github.event.inputs.skiptests, 'modules')
run: | run: |
./runtest-moduleapi --verbose --dump-logs --tls --dump-logs ${{github.event.inputs.test_args}} ./runtest-moduleapi --verbose --dump-logs --tls-module --dump-logs ${{github.event.inputs.test_args}}
- name: sentinel tests - name: sentinel tests
if: true && !contains(github.event.inputs.skiptests, 'sentinel') if: true && !contains(github.event.inputs.skiptests, 'sentinel')
run: | run: |
./runtest-sentinel --tls ${{github.event.inputs.cluster_test_args}} ./runtest-sentinel ${{github.event.inputs.cluster_test_args}}
- name: cluster tests - name: cluster tests
if: true && !contains(github.event.inputs.skiptests, 'cluster') if: true && !contains(github.event.inputs.skiptests, 'cluster')
run: | run: |
./runtest-cluster --tls ${{github.event.inputs.cluster_test_args}} ./runtest-cluster --tls-module ${{github.event.inputs.cluster_test_args}}
test-centos7-tls-no-tls: test-centos7-tls-no-tls:
runs-on: ubuntu-latest runs-on: ubuntu-latest
...@@ -582,7 +582,7 @@ jobs: ...@@ -582,7 +582,7 @@ jobs:
run: | run: |
yum -y install centos-release-scl epel-release yum -y install centos-release-scl epel-release
yum -y install devtoolset-7 openssl-devel openssl yum -y install devtoolset-7 openssl-devel openssl
scl enable devtoolset-7 "make BUILD_TLS=yes REDIS_CFLAGS='-Werror'" scl enable devtoolset-7 "make BUILD_TLS=module REDIS_CFLAGS='-Werror'"
- name: testprep - name: testprep
run: | run: |
yum -y install tcl tcltls tclx yum -y install tcl tcltls tclx
......
...@@ -9,8 +9,14 @@ Getting Started ...@@ -9,8 +9,14 @@ Getting Started
To build with TLS support you'll need OpenSSL development libraries (e.g. To build with TLS support you'll need OpenSSL development libraries (e.g.
libssl-dev on Debian/Ubuntu). libssl-dev on Debian/Ubuntu).
To build TLS support as Redis built-in:
Run `make BUILD_TLS=yes`. Run `make BUILD_TLS=yes`.
Or to build TLS as Redis module:
Run `make BUILD_TLS=module`.
Note that sentinel mode does not support TLS module.
### Tests ### Tests
To run Redis test suite with TLS, you'll need TLS support for TCL (i.e. To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
...@@ -22,16 +28,27 @@ To run Redis test suite with TLS, you'll need TLS support for TCL (i.e. ...@@ -22,16 +28,27 @@ To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run Redis and Redis 2. Run `./runtest --tls` or `./runtest-cluster --tls` to run Redis and Redis
Cluster tests in TLS mode. Cluster tests in TLS mode.
3. Run `./runtest --tls-module` or `./runtest-cluster --tls-module` to
run Redis and Redis cluster tests in TLS mode with Redis module.
### Running manually ### Running manually
To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was
invoked so sample certificates/keys are available): invoked so sample certificates/keys are available):
For TLS built-in mode:
./src/redis-server --tls-port 6379 --port 0 \ ./src/redis-server --tls-port 6379 --port 0 \
--tls-cert-file ./tests/tls/redis.crt \ --tls-cert-file ./tests/tls/redis.crt \
--tls-key-file ./tests/tls/redis.key \ --tls-key-file ./tests/tls/redis.key \
--tls-ca-cert-file ./tests/tls/ca.crt --tls-ca-cert-file ./tests/tls/ca.crt
For TLS module mode:
./src/redis-server --tls-port 6379 --port 0 \
--tls-cert-file ./tests/tls/redis.crt \
--tls-key-file ./tests/tls/redis.key \
--tls-ca-cert-file ./tests/tls/ca.crt \
--loadmodule src/redis-tls.so
To connect to this Redis server with `redis-cli`: To connect to this Redis server with `redis-cli`:
./src/redis-cli --tls \ ./src/redis-cli --tls \
......
...@@ -44,7 +44,7 @@ distclean: ...@@ -44,7 +44,7 @@ distclean:
.PHONY: distclean .PHONY: distclean
ifeq ($(BUILD_TLS),yes) ifneq (,$(filter $(BUILD_TLS),yes module))
HIREDIS_MAKE_FLAGS = USE_SSL=1 HIREDIS_MAKE_FLAGS = USE_SSL=1
endif endif
......
...@@ -267,24 +267,41 @@ ifeq ($(MALLOC),jemalloc) ...@@ -267,24 +267,41 @@ ifeq ($(MALLOC),jemalloc)
FINAL_LIBS := ../deps/jemalloc/lib/libjemalloc.a $(FINAL_LIBS) FINAL_LIBS := ../deps/jemalloc/lib/libjemalloc.a $(FINAL_LIBS)
endif endif
ifeq ($(BUILD_TLS),yes) # LIBSSL & LIBCRYPTO
FINAL_CFLAGS+=-DUSE_OPENSSL $(OPENSSL_CFLAGS) LIBSSL_LIBS=
FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS) LIBSSL_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libssl && echo $$?)
LIBSSL_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libssl && echo $$?)
ifeq ($(LIBSSL_PKGCONFIG),0) ifeq ($(LIBSSL_PKGCONFIG),0)
LIBSSL_LIBS=$(shell $(PKG_CONFIG) --libs libssl) LIBSSL_LIBS=$(shell $(PKG_CONFIG) --libs libssl)
else else
LIBSSL_LIBS=-lssl LIBSSL_LIBS=-lssl
endif endif
LIBCRYPTO_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libcrypto && echo $$?) LIBCRYPTO_LIBS=
LIBCRYPTO_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libcrypto && echo $$?)
ifeq ($(LIBCRYPTO_PKGCONFIG),0) ifeq ($(LIBCRYPTO_PKGCONFIG),0)
LIBCRYPTO_LIBS=$(shell $(PKG_CONFIG) --libs libcrypto) LIBCRYPTO_LIBS=$(shell $(PKG_CONFIG) --libs libcrypto)
else else
LIBCRYPTO_LIBS=-lcrypto LIBCRYPTO_LIBS=-lcrypto
endif endif
BUILD_NO:=0
BUILD_YES:=1
BUILD_MODULE:=2
ifeq ($(BUILD_TLS),yes)
FINAL_CFLAGS+=-DUSE_OPENSSL=$(BUILD_YES) $(OPENSSL_CFLAGS) -DBUILD_TLS_MODULE=$(BUILD_NO)
FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS)
FINAL_LIBS += ../deps/hiredis/libhiredis_ssl.a $(LIBSSL_LIBS) $(LIBCRYPTO_LIBS) FINAL_LIBS += ../deps/hiredis/libhiredis_ssl.a $(LIBSSL_LIBS) $(LIBCRYPTO_LIBS)
endif endif
TLS_MODULE=
TLS_MODULE_NAME:=redis-tls$(PROG_SUFFIX).so
TLS_MODULE_CFLAGS:=$(FINAL_CFLAGS)
ifeq ($(BUILD_TLS),module)
FINAL_CFLAGS+=-DUSE_OPENSSL=$(BUILD_MODULE) $(OPENSSL_CFLAGS)
TLS_CLIENT_LIBS = ../deps/hiredis/libhiredis_ssl.a $(LIBSSL_LIBS) $(LIBCRYPTO_LIBS)
TLS_MODULE=$(TLS_MODULE_NAME)
TLS_MODULE_CFLAGS+=-DUSE_OPENSSL=$(BUILD_MODULE) $(OPENSSL_CFLAGS) -DBUILD_TLS_MODULE=$(BUILD_MODULE)
endif
ifndef V ifndef V
define MAKE_INSTALL define MAKE_INSTALL
@printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$(1)$(ENDCOLOR) 1>&2 @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$(1)$(ENDCOLOR) 1>&2
...@@ -325,7 +342,7 @@ REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX) ...@@ -325,7 +342,7 @@ REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX)
REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX) REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX)
ALL_SOURCES=$(sort $(patsubst %.o,%.c,$(REDIS_SERVER_OBJ) $(REDIS_CLI_OBJ) $(REDIS_BENCHMARK_OBJ))) ALL_SOURCES=$(sort $(patsubst %.o,%.c,$(REDIS_SERVER_OBJ) $(REDIS_CLI_OBJ) $(REDIS_BENCHMARK_OBJ)))
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) $(TLS_MODULE)
@echo "" @echo ""
@echo "Hint: It's a good idea to run 'make test' ;)" @echo "Hint: It's a good idea to run 'make test' ;)"
@echo "" @echo ""
...@@ -385,13 +402,17 @@ $(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME) ...@@ -385,13 +402,17 @@ $(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME)
$(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME) $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME)
# redis-tls.so
$(TLS_MODULE_NAME): $(REDIS_SERVER_NAME)
$(QUIET_CC)$(CC) -o $@ tls.c -shared -fPIC $(TLS_MODULE_CFLAGS) $(TLS_CLIENT_LIBS)
# redis-cli # redis-cli
$(REDIS_CLI_NAME): $(REDIS_CLI_OBJ) $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
# redis-benchmark # redis-benchmark
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ) $(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/libhdrhistogram.a $(FINAL_LIBS) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/libhdrhistogram.a $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d) DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d)
-include $(DEP) -include $(DEP)
...@@ -410,7 +431,7 @@ commands.c: commands/*.json ../utils/generate-command-code.py ...@@ -410,7 +431,7 @@ commands.c: commands/*.json ../utils/generate-command-code.py
endif endif
clean: clean:
rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep *.so
rm -f $(DEP) rm -f $(DEP)
.PHONY: clean .PHONY: clean
......
...@@ -107,8 +107,6 @@ typedef struct ConnectionType { ...@@ -107,8 +107,6 @@ typedef struct ConnectionType {
/* TLS specified methods */ /* TLS specified methods */
sds (*get_peer_cert)(struct connection *conn); sds (*get_peer_cert)(struct connection *conn);
void* (*get_ctx)(void);
void* (*get_client_ctx)(void);
} ConnectionType; } ConnectionType;
struct connection { struct connection {
...@@ -355,15 +353,6 @@ int connKeepAlive(connection *conn, int interval); ...@@ -355,15 +353,6 @@ int connKeepAlive(connection *conn, int interval);
int connSendTimeout(connection *conn, long long ms); int connSendTimeout(connection *conn, long long ms);
int connRecvTimeout(connection *conn, long long ms); int connRecvTimeout(connection *conn, long long ms);
/* Helpers for tls special considerations */
static inline void *connTypeGetCtx(ConnectionType *ct) {
return ct->get_ctx();
}
static inline void *connTypeGetClientCtx(ConnectionType *ct) {
return ct->get_client_ctx();
}
/* Get cert for the secure connection */ /* Get cert for the secure connection */
static inline sds connGetPeerCert(connection *conn) { static inline sds connGetPeerCert(connection *conn) {
if (conn->type->get_peer_cert) { if (conn->type->get_peer_cert) {
...@@ -399,7 +388,7 @@ static inline connection *connCreate(ConnectionType *ct) { ...@@ -399,7 +388,7 @@ static inline connection *connCreate(ConnectionType *ct) {
return ct->conn_create(); return ct->conn_create();
} }
/* Create a accepted connection of specified type. /* Create an accepted connection of specified type.
* priv is connection type specified argument */ * priv is connection type specified argument */
static inline connection *connCreateAccepted(ConnectionType *ct, int fd, void *priv) { static inline connection *connCreateAccepted(ConnectionType *ct, int fd, void *priv) {
return ct->conn_create_accepted(fd, priv); return ct->conn_create_accepted(fd, priv);
......
...@@ -11,4 +11,6 @@ test -f release.h || touch release.h ...@@ -11,4 +11,6 @@ test -f release.h || touch release.h
echo "#define REDIS_GIT_SHA1 \"$GIT_SHA1\"" > release.h echo "#define REDIS_GIT_SHA1 \"$GIT_SHA1\"" > release.h
echo "#define REDIS_GIT_DIRTY \"$GIT_DIRTY\"" >> release.h echo "#define REDIS_GIT_DIRTY \"$GIT_DIRTY\"" >> release.h
echo "#define REDIS_BUILD_ID \"$BUILD_ID\"" >> release.h echo "#define REDIS_BUILD_ID \"$BUILD_ID\"" >> release.h
echo "#include \"version.h\"" >> release.h
echo "#define REDIS_BUILD_ID_RAW REDIS_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1" >> release.h
touch release.c # Force recompile of release.c touch release.c # Force recompile of release.c
...@@ -69,14 +69,14 @@ ...@@ -69,14 +69,14 @@
* pointers that have an API the module can call with them) * pointers that have an API the module can call with them)
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
   
typedef struct RedisModuleInfoCtx { struct RedisModuleInfoCtx {
struct RedisModule *module; struct RedisModule *module;
dict *requested_sections; dict *requested_sections;
sds info; /* info string we collected so far */ sds info; /* info string we collected so far */
int sections; /* number of sections we collected so far */ int sections; /* number of sections we collected so far */
int in_section; /* indication if we're in an active section or not */ int in_section; /* indication if we're in an active section or not */
int in_dict_field; /* indication that we're currently appending to a dict */ int in_dict_field; /* indication that we're currently appending to a dict */
} RedisModuleInfoCtx; };
   
/* This represents a shared API. Shared APIs will be used to populate /* This represents a shared API. Shared APIs will be used to populate
* the server.sharedapi dictionary, mapping names of APIs exported by * the server.sharedapi dictionary, mapping names of APIs exported by
...@@ -12211,13 +12211,13 @@ const char *RM_GetCurrentCommandName(RedisModuleCtx *ctx) { ...@@ -12211,13 +12211,13 @@ const char *RM_GetCurrentCommandName(RedisModuleCtx *ctx) {
/* The defrag context, used to manage state during calls to the data type /* The defrag context, used to manage state during calls to the data type
* defrag callback. * defrag callback.
*/ */
typedef struct RedisModuleDefragCtx { struct RedisModuleDefragCtx {
long defragged; long defragged;
long long int endtime; long long int endtime;
unsigned long *cursor; unsigned long *cursor;
struct redisObject *key; /* Optional name of key processed, NULL when unknown. */ struct redisObject *key; /* Optional name of key processed, NULL when unknown. */
int dbid; /* The dbid of the key being processed, -1 when unknown. */ int dbid; /* The dbid of the key being processed, -1 when unknown. */
} RedisModuleDefragCtx; };
   
/* Register a defrag callback for global data, i.e. anything that the module /* Register a defrag callback for global data, i.e. anything that the module
* may allocate that is not tied to a specific data type. * may allocate that is not tied to a specific data type.
......
...@@ -750,13 +750,41 @@ typedef enum { ...@@ -750,13 +750,41 @@ typedef enum {
REDISMODULE_ACL_LOG_CHANNEL /* Channel authorization failure */ REDISMODULE_ACL_LOG_CHANNEL /* Channel authorization failure */
} RedisModuleACLLogEntryReason; } RedisModuleACLLogEntryReason;
/* Incomplete structures needed by both the core and modules. */
typedef struct RedisModuleString RedisModuleString;
typedef struct RedisModuleIO RedisModuleIO;
typedef struct RedisModuleDigest RedisModuleDigest;
typedef struct RedisModuleInfoCtx RedisModuleInfoCtx;
typedef struct RedisModuleDefragCtx RedisModuleDefragCtx;
/* Function pointers needed by both the core and modules, these needs to be
* exposed since you can't cast a function pointer to (void *). */
typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
typedef void (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx);
typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
/* ------------------------- End of common defines ------------------------ */ /* ------------------------- End of common defines ------------------------ */
#ifndef REDISMODULE_CORE #if defined REDISMODULE_CORE
/* Things only defined for the modules core (server), not exported to modules
* that include this file. */
#define RedisModuleString robj
#endif /* defined REDISMODULE_CORE */
#if !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE
/* Things defined for modules, but not for core-modules. */
typedef long long mstime_t; typedef long long mstime_t;
typedef long long ustime_t; typedef long long ustime_t;
#endif /* !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE */
/* ----------- The rest of the defines are only for modules ----------------- */
#if !defined REDISMODULE_CORE || defined REDISMODULE_CORE_MODULE
/* Things defined for modules and core-modules. */
/* Macro definitions specific to individual compilers */ /* Macro definitions specific to individual compilers */
#ifndef REDISMODULE_ATTR_UNUSED #ifndef REDISMODULE_ATTR_UNUSED
# ifdef __GNUC__ # ifdef __GNUC__
...@@ -786,21 +814,16 @@ typedef long long ustime_t; ...@@ -786,21 +814,16 @@ typedef long long ustime_t;
typedef struct RedisModuleCtx RedisModuleCtx; typedef struct RedisModuleCtx RedisModuleCtx;
typedef struct RedisModuleCommand RedisModuleCommand; typedef struct RedisModuleCommand RedisModuleCommand;
typedef struct RedisModuleKey RedisModuleKey; typedef struct RedisModuleKey RedisModuleKey;
typedef struct RedisModuleString RedisModuleString;
typedef struct RedisModuleCallReply RedisModuleCallReply; typedef struct RedisModuleCallReply RedisModuleCallReply;
typedef struct RedisModuleIO RedisModuleIO;
typedef struct RedisModuleType RedisModuleType; typedef struct RedisModuleType RedisModuleType;
typedef struct RedisModuleDigest RedisModuleDigest;
typedef struct RedisModuleBlockedClient RedisModuleBlockedClient; typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
typedef struct RedisModuleClusterInfo RedisModuleClusterInfo; typedef struct RedisModuleClusterInfo RedisModuleClusterInfo;
typedef struct RedisModuleDict RedisModuleDict; typedef struct RedisModuleDict RedisModuleDict;
typedef struct RedisModuleDictIter RedisModuleDictIter; typedef struct RedisModuleDictIter RedisModuleDictIter;
typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx; typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx;
typedef struct RedisModuleCommandFilter RedisModuleCommandFilter; typedef struct RedisModuleCommandFilter RedisModuleCommandFilter;
typedef struct RedisModuleInfoCtx RedisModuleInfoCtx;
typedef struct RedisModuleServerInfoData RedisModuleServerInfoData; typedef struct RedisModuleServerInfoData RedisModuleServerInfoData;
typedef struct RedisModuleScanCursor RedisModuleScanCursor; typedef struct RedisModuleScanCursor RedisModuleScanCursor;
typedef struct RedisModuleDefragCtx RedisModuleDefragCtx;
typedef struct RedisModuleUser RedisModuleUser; typedef struct RedisModuleUser RedisModuleUser;
typedef struct RedisModuleKeyOptCtx RedisModuleKeyOptCtx; typedef struct RedisModuleKeyOptCtx RedisModuleKeyOptCtx;
...@@ -827,11 +850,8 @@ typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const cha ...@@ -827,11 +850,8 @@ typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const cha
typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data); typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data);
typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter); typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter);
typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data); typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data);
typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keyname, RedisModuleKey *key, void *privdata); typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keyname, RedisModuleKey *key, void *privdata);
typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata); typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata);
typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
typedef int (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx);
typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata); typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata);
typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata); typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata);
typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata); typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata);
...@@ -1559,11 +1579,5 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int ...@@ -1559,11 +1579,5 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
#define RMAPI_FUNC_SUPPORTED(func) (func != NULL) #define RMAPI_FUNC_SUPPORTED(func) (func != NULL)
#else
/* Things only defined for the modules core, not exported to modules
* including this file. */
#define RedisModuleString robj
#endif /* REDISMODULE_CORE */ #endif /* REDISMODULE_CORE */
#endif /* REDISMODULE_H */ #endif /* REDISMODULE_H */
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include <stdio.h> #include <stdio.h>
#include "release.h" #include "release.h"
#include "version.h"
#include "crc64.h" #include "crc64.h"
char *redisGitSHA1(void) { char *redisGitSHA1(void) {
...@@ -46,8 +45,12 @@ char *redisGitDirty(void) { ...@@ -46,8 +45,12 @@ char *redisGitDirty(void) {
return REDIS_GIT_DIRTY; return REDIS_GIT_DIRTY;
} }
const char *redisBuildIdRaw(void) {
return REDIS_BUILD_ID_RAW;
}
uint64_t redisBuildId(void) { uint64_t redisBuildId(void) {
char *buildid = REDIS_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1; char *buildid = REDIS_BUILD_ID_RAW;
return crc64(0,(unsigned char*)buildid,strlen(buildid)); return crc64(0,(unsigned char*)buildid,strlen(buildid));
} }
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "server.h" #include "server.h"
#include "hiredis.h" #include "hiredis.h"
#ifdef USE_OPENSSL #if USE_OPENSSL == 1 /* BUILD_YES */
#include "openssl/ssl.h" #include "openssl/ssl.h"
#include "hiredis_ssl.h" #include "hiredis_ssl.h"
#endif #endif
...@@ -44,6 +44,11 @@ ...@@ -44,6 +44,11 @@
extern char **environ; extern char **environ;
#if USE_OPENSSL == 1 /* BUILD_YES */
extern SSL_CTX *redis_tls_ctx;
extern SSL_CTX *redis_tls_client_ctx;
#endif
#define REDIS_SENTINEL_PORT 26379 #define REDIS_SENTINEL_PORT 26379
/* ======================== Sentinel global state =========================== */ /* ======================== Sentinel global state =========================== */
...@@ -2373,12 +2378,7 @@ void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, char ...@@ -2373,12 +2378,7 @@ void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, char
} }
static int instanceLinkNegotiateTLS(redisAsyncContext *context) { static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
#ifndef USE_OPENSSL #if USE_OPENSSL == 1 /* BUILD_YES */
(void) context;
#else
SSL_CTX *redis_tls_ctx = connTypeGetCtx(connectionTypeTls());
SSL_CTX *redis_tls_client_ctx = connTypeGetClientCtx(connectionTypeTls());
if (!redis_tls_ctx) return C_ERR; if (!redis_tls_ctx) return C_ERR;
SSL *ssl = SSL_new(redis_tls_client_ctx ? redis_tls_client_ctx : redis_tls_ctx); SSL *ssl = SSL_new(redis_tls_client_ctx ? redis_tls_client_ctx : redis_tls_ctx);
if (!ssl) return C_ERR; if (!ssl) return C_ERR;
...@@ -2387,6 +2387,8 @@ static int instanceLinkNegotiateTLS(redisAsyncContext *context) { ...@@ -2387,6 +2387,8 @@ static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
SSL_free(ssl); SSL_free(ssl);
return C_ERR; return C_ERR;
} }
#else
UNUSED(context);
#endif #endif
return C_OK; return C_OK;
} }
......
...@@ -2446,12 +2446,6 @@ void initServer(void) { ...@@ -2446,12 +2446,6 @@ void initServer(void) {
exit(1); exit(1);
} }
if ((server.tls_port || server.tls_replication || server.tls_cluster)
&& connTypeConfigure(connectionTypeTls(), &server.tls_ctx_config, 1) == C_ERR) {
serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
exit(1);
}
for (j = 0; j < CLIENT_MEM_USAGE_BUCKETS; j++) { for (j = 0; j < CLIENT_MEM_USAGE_BUCKETS; j++) {
server.client_mem_usage_buckets[j].mem_usage_sum = 0; server.client_mem_usage_buckets[j].mem_usage_sum = 0;
server.client_mem_usage_buckets[j].clients = listCreate(); server.client_mem_usage_buckets[j].clients = listCreate();
...@@ -2470,40 +2464,6 @@ void initServer(void) { ...@@ -2470,40 +2464,6 @@ void initServer(void) {
} }
server.db = zmalloc(sizeof(redisDb)*server.dbnum); server.db = zmalloc(sizeof(redisDb)*server.dbnum);
/* Setup listeners from server config for TCP/TLS/Unix */
int conn_index;
connListener *listener;
if (server.port != 0) {
conn_index = connectionIndexByType(CONN_TYPE_SOCKET);
if (conn_index < 0)
serverPanic("Failed finding connection listener of %s", CONN_TYPE_SOCKET);
listener = &server.listeners[conn_index];
listener->bindaddr = server.bindaddr;
listener->bindaddr_count = server.bindaddr_count;
listener->port = server.port;
listener->ct = connectionByType(CONN_TYPE_SOCKET);
}
if (server.tls_port != 0) {
conn_index = connectionIndexByType(CONN_TYPE_TLS);
if (conn_index < 0)
serverPanic("Failed finding connection listener of %s", CONN_TYPE_TLS);
listener = &server.listeners[conn_index];
listener->bindaddr = server.bindaddr;
listener->bindaddr_count = server.bindaddr_count;
listener->port = server.tls_port;
listener->ct = connectionByType(CONN_TYPE_TLS);
}
if (server.unixsocket != NULL) {
conn_index = connectionIndexByType(CONN_TYPE_UNIX);
if (conn_index < 0)
serverPanic("Failed finding connection listener of %s", CONN_TYPE_UNIX);
listener = &server.listeners[conn_index];
listener->bindaddr = &server.unixsocket;
listener->bindaddr_count = 1;
listener->ct = connectionByType(CONN_TYPE_UNIX);
listener->priv = &server.unixsocketperm; /* Unix socket specified */
}
/* Create the Redis databases, and initialize other internal state. */ /* Create the Redis databases, and initialize other internal state. */
for (j = 0; j < server.dbnum; j++) { for (j = 0; j < server.dbnum; j++) {
server.db[j].dict = dictCreate(&dbDictType); server.db[j].dict = dictCreate(&dbDictType);
...@@ -2584,29 +2544,6 @@ void initServer(void) { ...@@ -2584,29 +2544,6 @@ void initServer(void) {
exit(1); exit(1);
} }
/* create all the configured listener, and add handler to start to accept */
int listen_fds = 0;
for (j = 0; j < CONN_TYPE_MAX; j++) {
listener = &server.listeners[j];
if (listener->ct == NULL)
continue;
if (connListen(listener) == C_ERR) {
serverLog(LL_WARNING, "Failed listening on port %u (%s), aborting.", listener->port, listener->ct->get_type(NULL));
exit(1);
}
if (createSocketAcceptHandler(listener, connAcceptHandler(listener->ct)) != C_OK)
serverPanic("Unrecoverable error creating %s listener accept handler.", listener->ct->get_type(NULL));
listen_fds += listener->count;
}
if (listen_fds == 0) {
serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
exit(1);
}
/* Register a readable event for the pipe used to awake the event loop /* Register a readable event for the pipe used to awake the event loop
* from module threads. */ * from module threads. */
if (aeCreateFileEvent(server.el, server.module_pipe[0], AE_READABLE, if (aeCreateFileEvent(server.el, server.module_pipe[0], AE_READABLE,
...@@ -2630,7 +2567,6 @@ void initServer(void) { ...@@ -2630,7 +2567,6 @@ void initServer(void) {
server.maxmemory_policy = MAXMEMORY_NO_EVICTION; server.maxmemory_policy = MAXMEMORY_NO_EVICTION;
} }
if (server.cluster_enabled) clusterInit();
scriptingInit(1); scriptingInit(1);
functionsInit(); functionsInit();
slowlogInit(); slowlogInit();
...@@ -2642,6 +2578,78 @@ void initServer(void) { ...@@ -2642,6 +2578,78 @@ void initServer(void) {
applyWatchdogPeriod(); applyWatchdogPeriod();
} }
void initListeners() {
/* Setup listeners from server config for TCP/TLS/Unix */
int conn_index;
connListener *listener;
if (server.port != 0) {
conn_index = connectionIndexByType(CONN_TYPE_SOCKET);
if (conn_index < 0)
serverPanic("Failed finding connection listener of %s", CONN_TYPE_SOCKET);
listener = &server.listeners[conn_index];
listener->bindaddr = server.bindaddr;
listener->bindaddr_count = server.bindaddr_count;
listener->port = server.port;
listener->ct = connectionByType(CONN_TYPE_SOCKET);
}
if (server.tls_port || server.tls_replication || server.tls_cluster) {
ConnectionType *ct_tls = connectionTypeTls();
if (!ct_tls) {
serverLog(LL_WARNING, "Failed finding TLS support.");
exit(1);
}
if (connTypeConfigure(ct_tls, &server.tls_ctx_config, 1) == C_ERR) {
serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
exit(1);
}
}
if (server.tls_port != 0) {
conn_index = connectionIndexByType(CONN_TYPE_TLS);
if (conn_index < 0)
serverPanic("Failed finding connection listener of %s", CONN_TYPE_TLS);
listener = &server.listeners[conn_index];
listener->bindaddr = server.bindaddr;
listener->bindaddr_count = server.bindaddr_count;
listener->port = server.tls_port;
listener->ct = connectionByType(CONN_TYPE_TLS);
}
if (server.unixsocket != NULL) {
conn_index = connectionIndexByType(CONN_TYPE_UNIX);
if (conn_index < 0)
serverPanic("Failed finding connection listener of %s", CONN_TYPE_UNIX);
listener = &server.listeners[conn_index];
listener->bindaddr = &server.unixsocket;
listener->bindaddr_count = 1;
listener->ct = connectionByType(CONN_TYPE_UNIX);
listener->priv = &server.unixsocketperm; /* Unix socket specified */
}
/* create all the configured listener, and add handler to start to accept */
int listen_fds = 0;
for (int j = 0; j < CONN_TYPE_MAX; j++) {
listener = &server.listeners[j];
if (listener->ct == NULL)
continue;
if (connListen(listener) == C_ERR) {
serverLog(LL_WARNING, "Failed listening on port %u (%s), aborting.", listener->port, listener->ct->get_type(NULL));
exit(1);
}
if (createSocketAcceptHandler(listener, connAcceptHandler(listener->ct)) != C_OK)
serverPanic("Unrecoverable error creating %s listener accept handler.", listener->ct->get_type(NULL));
listen_fds += listener->count;
}
if (listen_fds == 0) {
serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
exit(1);
}
}
/* Some steps in server initialization need to be done last (after modules /* Some steps in server initialization need to be done last (after modules
* are loaded). * are loaded).
* Specifically, creation of threads due to a race bug in ld.so, in which * Specifically, creation of threads due to a race bug in ld.so, in which
...@@ -7086,6 +7094,16 @@ int main(int argc, char **argv) { ...@@ -7086,6 +7094,16 @@ int main(int argc, char **argv) {
if (server.set_proc_title) redisSetProcTitle(NULL); if (server.set_proc_title) redisSetProcTitle(NULL);
redisAsciiArt(); redisAsciiArt();
checkTcpBacklogSettings(); checkTcpBacklogSettings();
if (!server.sentinel_mode) {
moduleInitModulesSystemLast();
moduleLoadFromQueue();
}
ACLLoadUsersAtStartup();
initListeners();
if (server.cluster_enabled) {
clusterInit();
}
InitServerLast();
if (!server.sentinel_mode) { if (!server.sentinel_mode) {
/* Things not needed when running in Sentinel mode. */ /* Things not needed when running in Sentinel mode. */
...@@ -7114,10 +7132,6 @@ int main(int argc, char **argv) { ...@@ -7114,10 +7132,6 @@ int main(int argc, char **argv) {
} }
#endif /* __arm64__ */ #endif /* __arm64__ */
#endif /* __linux__ */ #endif /* __linux__ */
moduleInitModulesSystemLast();
moduleLoadFromQueue();
ACLLoadUsersAtStartup();
InitServerLast();
aofLoadManifestFromDisk(); aofLoadManifestFromDisk();
loadDataFromDisk(); loadDataFromDisk();
aofOpenIfNeededOnServerStart(); aofOpenIfNeededOnServerStart();
...@@ -7148,8 +7162,6 @@ int main(int argc, char **argv) { ...@@ -7148,8 +7162,6 @@ int main(int argc, char **argv) {
redisCommunicateSystemd("READY=1\n"); redisCommunicateSystemd("READY=1\n");
} }
} else { } else {
ACLLoadUsersAtStartup();
InitServerLast();
sentinelIsRunning(); sentinelIsRunning();
if (server.supervised_mode == SUPERVISED_SYSTEMD) { if (server.supervised_mode == SUPERVISED_SYSTEMD) {
redisCommunicateSystemd("STATUS=Ready to accept connections\n"); redisCommunicateSystemd("STATUS=Ready to accept connections\n");
......
...@@ -81,6 +81,7 @@ typedef long long ustime_t; /* microsecond time type. */ ...@@ -81,6 +81,7 @@ typedef long long ustime_t; /* microsecond time type. */
#include "connection.h" /* Connection abstraction */ #include "connection.h" /* Connection abstraction */
#define REDISMODULE_CORE 1 #define REDISMODULE_CORE 1
typedef struct redisObject robj;
#include "redismodule.h" /* Redis modules API defines. */ #include "redismodule.h" /* Redis modules API defines. */
/* Following includes allow test functions to be called from Redis main() */ /* Following includes allow test functions to be called from Redis main() */
...@@ -679,9 +680,6 @@ struct RedisModuleIO; ...@@ -679,9 +680,6 @@ struct RedisModuleIO;
struct RedisModuleDigest; struct RedisModuleDigest;
struct RedisModuleCtx; struct RedisModuleCtx;
struct moduleLoadQueueEntry; struct moduleLoadQueueEntry;
struct redisObject;
struct RedisModuleDefragCtx;
struct RedisModuleInfoCtx;
struct RedisModuleKeyOptCtx; struct RedisModuleKeyOptCtx;
struct RedisModuleCommand; struct RedisModuleCommand;
...@@ -701,20 +699,12 @@ typedef size_t (*moduleTypeFreeEffortFunc)(struct redisObject *key, const void * ...@@ -701,20 +699,12 @@ typedef size_t (*moduleTypeFreeEffortFunc)(struct redisObject *key, const void *
typedef void (*moduleTypeUnlinkFunc)(struct redisObject *key, void *value); typedef void (*moduleTypeUnlinkFunc)(struct redisObject *key, void *value);
typedef void *(*moduleTypeCopyFunc)(struct redisObject *fromkey, struct redisObject *tokey, const void *value); typedef void *(*moduleTypeCopyFunc)(struct redisObject *fromkey, struct redisObject *tokey, const void *value);
typedef int (*moduleTypeDefragFunc)(struct RedisModuleDefragCtx *ctx, struct redisObject *key, void **value); typedef int (*moduleTypeDefragFunc)(struct RedisModuleDefragCtx *ctx, struct redisObject *key, void **value);
typedef void (*RedisModuleInfoFunc)(struct RedisModuleInfoCtx *ctx, int for_crash_report);
typedef void (*RedisModuleDefragFunc)(struct RedisModuleDefragCtx *ctx);
typedef size_t (*moduleTypeMemUsageFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size); typedef size_t (*moduleTypeMemUsageFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size);
typedef void (*moduleTypeFreeFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value); typedef void (*moduleTypeFreeFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef size_t (*moduleTypeFreeEffortFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value); typedef size_t (*moduleTypeFreeEffortFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
typedef void (*moduleTypeUnlinkFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value); typedef void (*moduleTypeUnlinkFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef void *(*moduleTypeCopyFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value); typedef void *(*moduleTypeCopyFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
/* This callback type is called by moduleNotifyUserChanged() every time
* a user authenticated via the module API is associated with a different
* user or gets disconnected. This needs to be exposed since you can't cast
* a function pointer to (void *). */
typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
/* The module type, which is referenced in each value of a given type, defines /* The module type, which is referenced in each value of a given type, defines
* the methods and links to the module exporting the type. */ * the methods and links to the module exporting the type. */
...@@ -786,7 +776,7 @@ typedef struct RedisModule RedisModule; ...@@ -786,7 +776,7 @@ typedef struct RedisModule RedisModule;
/* This is a wrapper for the 'rio' streams used inside rdb.c in Redis, so that /* This is a wrapper for the 'rio' streams used inside rdb.c in Redis, so that
* the user does not have to take the total count of the written bytes nor * the user does not have to take the total count of the written bytes nor
* to care about error conditions. */ * to care about error conditions. */
typedef struct RedisModuleIO { struct RedisModuleIO {
size_t bytes; /* Bytes read / written so far. */ size_t bytes; /* Bytes read / written so far. */
rio *rio; /* Rio stream. */ rio *rio; /* Rio stream. */
moduleType *type; /* Module type doing the operation. */ moduleType *type; /* Module type doing the operation. */
...@@ -794,7 +784,7 @@ typedef struct RedisModuleIO { ...@@ -794,7 +784,7 @@ typedef struct RedisModuleIO {
struct RedisModuleCtx *ctx; /* Optional context, see RM_GetContextFromIO()*/ struct RedisModuleCtx *ctx; /* Optional context, see RM_GetContextFromIO()*/
struct redisObject *key; /* Optional name of key processed */ struct redisObject *key; /* Optional name of key processed */
int dbid; /* The dbid of the key being processed, -1 when unknown. */ int dbid; /* The dbid of the key being processed, -1 when unknown. */
} RedisModuleIO; };
/* Macro to initialize an IO context. Note that the 'ver' field is populated /* Macro to initialize an IO context. Note that the 'ver' field is populated
* inside rdb.c according to the version of the value to load. */ * inside rdb.c according to the version of the value to load. */
...@@ -813,12 +803,12 @@ typedef struct RedisModuleIO { ...@@ -813,12 +803,12 @@ typedef struct RedisModuleIO {
* a data structure, so that a digest can be created in a way that correctly * a data structure, so that a digest can be created in a way that correctly
* reflects the values. See the DEBUG DIGEST command implementation for more * reflects the values. See the DEBUG DIGEST command implementation for more
* background. */ * background. */
typedef struct RedisModuleDigest { struct RedisModuleDigest {
unsigned char o[20]; /* Ordered elements. */ unsigned char o[20]; /* Ordered elements. */
unsigned char x[20]; /* Xored elements. */ unsigned char x[20]; /* Xored elements. */
struct redisObject *key; /* Optional name of key processed */ struct redisObject *key; /* Optional name of key processed */
int dbid; /* The dbid of the key being processed */ int dbid; /* The dbid of the key being processed */
} RedisModuleDigest; };
/* Just start with a digest composed of all zero bytes. */ /* Just start with a digest composed of all zero bytes. */
#define moduleInitDigestContext(mdvar) do { \ #define moduleInitDigestContext(mdvar) do { \
...@@ -849,7 +839,7 @@ typedef struct RedisModuleDigest { ...@@ -849,7 +839,7 @@ typedef struct RedisModuleDigest {
#define OBJ_SHARED_REFCOUNT INT_MAX /* Global object never destroyed. */ #define OBJ_SHARED_REFCOUNT INT_MAX /* Global object never destroyed. */
#define OBJ_STATIC_REFCOUNT (INT_MAX-1) /* Object allocated in the stack. */ #define OBJ_STATIC_REFCOUNT (INT_MAX-1) /* Object allocated in the stack. */
#define OBJ_FIRST_SPECIAL_REFCOUNT OBJ_STATIC_REFCOUNT #define OBJ_FIRST_SPECIAL_REFCOUNT OBJ_STATIC_REFCOUNT
typedef struct redisObject { struct redisObject {
unsigned type:4; unsigned type:4;
unsigned encoding:4; unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
...@@ -857,7 +847,7 @@ typedef struct redisObject { ...@@ -857,7 +847,7 @@ typedef struct redisObject {
* and most significant 16 bits access time). */ * and most significant 16 bits access time). */
int refcount; int refcount;
void *ptr; void *ptr;
} robj; };
/* The a string name for an object's type as listed above /* The a string name for an object's type as listed above
* Native types are checked against the OBJ_STRING, OBJ_LIST, OBJ_* defines, * Native types are checked against the OBJ_STRING, OBJ_LIST, OBJ_* defines,
...@@ -3269,6 +3259,7 @@ void *dictSdsDup(dict *d, const void *key); ...@@ -3269,6 +3259,7 @@ void *dictSdsDup(dict *d, const void *key);
char *redisGitSHA1(void); char *redisGitSHA1(void);
char *redisGitDirty(void); char *redisGitDirty(void);
uint64_t redisBuildId(void); uint64_t redisBuildId(void);
const char *redisBuildIdRaw(void);
char *redisBuildIdString(void); char *redisBuildIdString(void);
/* Commands prototypes */ /* Commands prototypes */
......
...@@ -27,12 +27,13 @@ ...@@ -27,12 +27,13 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#define REDISMODULE_CORE_MODULE /* A module that's part of the redis core, uses server.h too. */
#include "server.h" #include "server.h"
#include "connhelpers.h" #include "connhelpers.h"
#include "adlist.h" #include "adlist.h"
#ifdef USE_OPENSSL #if (USE_OPENSSL == 1 /* BUILD_YES */ ) || ((USE_OPENSSL == 2 /* BUILD_MODULE */) && (BUILD_TLS_MODULE == 2))
#include <openssl/conf.h> #include <openssl/conf.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
...@@ -56,8 +57,8 @@ ...@@ -56,8 +57,8 @@
#define REDIS_TLS_PROTO_DEFAULT (REDIS_TLS_PROTO_TLSv1_2) #define REDIS_TLS_PROTO_DEFAULT (REDIS_TLS_PROTO_TLSv1_2)
#endif #endif
static SSL_CTX *redis_tls_ctx = NULL; SSL_CTX *redis_tls_ctx = NULL;
static SSL_CTX *redis_tls_client_ctx = NULL; SSL_CTX *redis_tls_client_ctx = NULL;
static int parseProtocolsConfig(const char *str) { static int parseProtocolsConfig(const char *str) {
int i, count = 0; int i, count = 0;
...@@ -1087,14 +1088,6 @@ static sds connTLSGetPeerCert(connection *conn_) { ...@@ -1087,14 +1088,6 @@ static sds connTLSGetPeerCert(connection *conn_) {
return cert_pem; return cert_pem;
} }
static void *tlsGetCtx(void) {
return redis_tls_ctx;
}
static void *tlsGetClientCtx(void) {
return redis_tls_client_ctx;
}
static ConnectionType CT_TLS = { static ConnectionType CT_TLS = {
/* connection type */ /* connection type */
.get_type = connTLSGetType, .get_type = connTLSGetType,
...@@ -1137,20 +1130,55 @@ static ConnectionType CT_TLS = { ...@@ -1137,20 +1130,55 @@ static ConnectionType CT_TLS = {
/* TLS specified methods */ /* TLS specified methods */
.get_peer_cert = connTLSGetPeerCert, .get_peer_cert = connTLSGetPeerCert,
.get_ctx = tlsGetCtx,
.get_client_ctx = tlsGetClientCtx
}; };
int RedisRegisterConnectionTypeTLS() int RedisRegisterConnectionTypeTLS() {
{
return connTypeRegister(&CT_TLS); return connTypeRegister(&CT_TLS);
} }
#else /* USE_OPENSSL */ #else /* USE_OPENSSL */
int RedisRegisterConnectionTypeTLS() int RedisRegisterConnectionTypeTLS() {
{ serverLog(LL_VERBOSE, "Connection type %s not builtin", CONN_TYPE_TLS);
return C_ERR; return C_ERR;
} }
#endif #endif
#if BUILD_TLS_MODULE == 2 /* BUILD_MODULE */
#include "release.h"
int RedisModule_OnLoad(void *ctx, RedisModuleString **argv, int argc) {
UNUSED(argv);
UNUSED(argc);
/* Connection modules must be part of the same build as redis. */
if (strcmp(REDIS_BUILD_ID_RAW, redisBuildIdRaw())) {
serverLog(LL_NOTICE, "Connection type %s was not built together with the redis-server used.", CONN_TYPE_TLS);
return REDISMODULE_ERR;
}
if (RedisModule_Init(ctx,"tls",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
/* Connection modules is available only bootup. */
if ((RedisModule_GetContextFlags(ctx) & REDISMODULE_CTX_FLAGS_SERVER_STARTUP) == 0) {
serverLog(LL_NOTICE, "Connection type %s can be loaded only during bootup", CONN_TYPE_TLS);
return REDISMODULE_ERR;
}
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD);
if(connTypeRegister(&CT_TLS) != C_OK)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}
int RedisModule_OnUnload(void *arg) {
UNUSED(arg);
serverLog(LL_NOTICE, "Connection type %s can not be unloaded", CONN_TYPE_TLS);
return REDISMODULE_ERR;
}
#endif
...@@ -19,6 +19,7 @@ source ../support/test.tcl ...@@ -19,6 +19,7 @@ source ../support/test.tcl
set ::verbose 0 set ::verbose 0
set ::valgrind 0 set ::valgrind 0
set ::tls 0 set ::tls 0
set ::tls_module 0
set ::pause_on_error 0 set ::pause_on_error 0
set ::dont_clean 0 set ::dont_clean 0
set ::simulate_error 0 set ::simulate_error 0
...@@ -85,6 +86,10 @@ proc spawn_instance {type base_port count {conf {}} {base_conf_file ""}} { ...@@ -85,6 +86,10 @@ proc spawn_instance {type base_port count {conf {}} {base_conf_file ""}} {
} }
if {$::tls} { if {$::tls} {
if {$::tls_module} {
puts $cfg [format "loadmodule %s/../../../src/redis-tls.so" [pwd]]
}
puts $cfg "tls-port $port" puts $cfg "tls-port $port"
puts $cfg "tls-replication yes" puts $cfg "tls-replication yes"
puts $cfg "tls-cluster yes" puts $cfg "tls-cluster yes"
...@@ -271,13 +276,16 @@ proc parse_options {} { ...@@ -271,13 +276,16 @@ proc parse_options {} {
} elseif {$opt eq {--host}} { } elseif {$opt eq {--host}} {
incr j incr j
set ::host ${val} set ::host ${val}
} elseif {$opt eq {--tls}} { } elseif {$opt eq {--tls} || $opt eq {--tls-module}} {
package require tls 1.6 package require tls 1.6
::tls::init \ ::tls::init \
-cafile "$::tlsdir/ca.crt" \ -cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/client.crt" \ -certfile "$::tlsdir/client.crt" \
-keyfile "$::tlsdir/client.key" -keyfile "$::tlsdir/client.key"
set ::tls 1 set ::tls 1
if {$opt eq {--tls-module}} {
set ::tls_module 1
}
} elseif {$opt eq {--config}} { } elseif {$opt eq {--config}} {
set val2 [lindex $::argv [expr $j+2]] set val2 [lindex $::argv [expr $j+2]]
dict set ::global_config $val $val2 dict set ::global_config $val $val2
...@@ -293,6 +301,7 @@ proc parse_options {} { ...@@ -293,6 +301,7 @@ proc parse_options {} {
puts "--fail Simulate a test failure." puts "--fail Simulate a test failure."
puts "--valgrind Run with valgrind." puts "--valgrind Run with valgrind."
puts "--tls Run tests in TLS mode." puts "--tls Run tests in TLS mode."
puts "--tls-module Run tests in TLS mode with Redis module."
puts "--host <host> Use hostname instead of 127.0.0.1." puts "--host <host> Use hostname instead of 127.0.0.1."
puts "--config <k> <v> Extra config argument(s)." puts "--config <k> <v> Extra config argument(s)."
puts "--stop Blocks once the first test fails." puts "--stop Blocks once the first test fails."
......
...@@ -35,7 +35,7 @@ static void createGlobalStrings(RedisModuleCtx *ctx, int count) ...@@ -35,7 +35,7 @@ static void createGlobalStrings(RedisModuleCtx *ctx, int count)
} }
} }
static int defragGlobalStrings(RedisModuleDefragCtx *ctx) static void defragGlobalStrings(RedisModuleDefragCtx *ctx)
{ {
for (int i = 0; i < global_strings_len; i++) { for (int i = 0; i < global_strings_len; i++) {
RedisModuleString *new = RedisModule_DefragRedisModuleString(ctx, global_strings[i]); RedisModuleString *new = RedisModule_DefragRedisModuleString(ctx, global_strings[i]);
...@@ -45,8 +45,6 @@ static int defragGlobalStrings(RedisModuleDefragCtx *ctx) ...@@ -45,8 +45,6 @@ static int defragGlobalStrings(RedisModuleDefragCtx *ctx)
global_defragged++; global_defragged++;
} }
} }
return 0;
} }
static void FragInfo(RedisModuleInfoCtx *ctx, int for_crash_report) { static void FragInfo(RedisModuleInfoCtx *ctx, int for_crash_report) {
......
...@@ -300,7 +300,7 @@ proc wait_server_started {config_file stdout pid} { ...@@ -300,7 +300,7 @@ proc wait_server_started {config_file stdout pid} {
set maxiter [expr {120*1000/$checkperiod}] ; # Wait up to 2 minutes. set maxiter [expr {120*1000/$checkperiod}] ; # Wait up to 2 minutes.
set port_busy 0 set port_busy 0
while 1 { while 1 {
if {[regexp -- " PID: $pid" [exec cat $stdout]]} { if {[regexp -- " PID: $pid.*Server initialized" [exec cat $stdout]]} {
break break
} }
after $checkperiod after $checkperiod
...@@ -464,6 +464,9 @@ proc start_server {options {code undefined}} { ...@@ -464,6 +464,9 @@ proc start_server {options {code undefined}} {
set data [split [exec cat "tests/assets/$baseconfig"] "\n"] set data [split [exec cat "tests/assets/$baseconfig"] "\n"]
set config {} set config {}
if {$::tls} { if {$::tls} {
if {$::tls_module} {
lappend config_lines [list "loadmodule" [format "%s/src/redis-tls.so" [pwd]]]
}
dict set config "tls-cert-file" [format "%s/tests/tls/server.crt" [pwd]] dict set config "tls-cert-file" [format "%s/tests/tls/server.crt" [pwd]]
dict set config "tls-key-file" [format "%s/tests/tls/server.key" [pwd]] dict set config "tls-key-file" [format "%s/tests/tls/server.key" [pwd]]
dict set config "tls-client-cert-file" [format "%s/tests/tls/client.crt" [pwd]] dict set config "tls-client-cert-file" [format "%s/tests/tls/client.crt" [pwd]]
......
...@@ -1039,3 +1039,25 @@ proc memory_usage {key} { ...@@ -1039,3 +1039,25 @@ proc memory_usage {key} {
} }
return $usage return $usage
} }
# forward compatibility, lmap missing in TCL 8.5
proc lmap args {
set body [lindex $args end]
set args [lrange $args 0 end-1]
set n 0
set pairs [list]
foreach {varnames listval} $args {
set varlist [list]
foreach varname $varnames {
upvar 1 $varname var$n
lappend varlist var$n
incr n
}
lappend pairs $varlist $listval
}
set temp [list]
foreach {*}$pairs {
lappend temp [uplevel 1 $body]
}
set temp
}
...@@ -111,6 +111,7 @@ set ::traceleaks 0 ...@@ -111,6 +111,7 @@ set ::traceleaks 0
set ::valgrind 0 set ::valgrind 0
set ::durable 0 set ::durable 0
set ::tls 0 set ::tls 0
set ::tls_module 0
set ::stack_logging 0 set ::stack_logging 0
set ::verbose 0 set ::verbose 0
set ::quiet 0 set ::quiet 0
...@@ -611,6 +612,7 @@ proc print_help_screen {} { ...@@ -611,6 +612,7 @@ proc print_help_screen {} {
"--wait-server Wait after server is started (so that you can attach a debugger)." "--wait-server Wait after server is started (so that you can attach a debugger)."
"--dump-logs Dump server log on test failure." "--dump-logs Dump server log on test failure."
"--tls Run tests in TLS mode." "--tls Run tests in TLS mode."
"--tls-module Run tests in TLS mode with Redis module."
"--host <addr> Run tests against an external host." "--host <addr> Run tests against an external host."
"--port <port> TCP port to use against external host." "--port <port> TCP port to use against external host."
"--baseport <port> Initial port number for spawned redis servers." "--baseport <port> Initial port number for spawned redis servers."
...@@ -659,13 +661,16 @@ for {set j 0} {$j < [llength $argv]} {incr j} { ...@@ -659,13 +661,16 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
} }
} elseif {$opt eq {--quiet}} { } elseif {$opt eq {--quiet}} {
set ::quiet 1 set ::quiet 1
} elseif {$opt eq {--tls}} { } elseif {$opt eq {--tls} || $opt eq {--tls-module}} {
package require tls 1.6 package require tls 1.6
set ::tls 1 set ::tls 1
::tls::init \ ::tls::init \
-cafile "$::tlsdir/ca.crt" \ -cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/client.crt" \ -certfile "$::tlsdir/client.crt" \
-keyfile "$::tlsdir/client.key" -keyfile "$::tlsdir/client.key"
if {$opt eq {--tls-module}} {
set ::tls_module 1
}
} elseif {$opt eq {--host}} { } elseif {$opt eq {--host}} {
set ::external 1 set ::external 1
set ::host $arg set ::host $arg
......
...@@ -5,18 +5,21 @@ test {modules config rewrite} { ...@@ -5,18 +5,21 @@ test {modules config rewrite} {
start_server {tags {"modules"}} { start_server {tags {"modules"}} {
r module load $testmodule r module load $testmodule
assert_equal [lindex [lindex [r module list] 0] 1] infotest set modules [lmap x [r module list] {dict get $x name}]
assert_not_equal [lsearch $modules infotest] -1
r config rewrite r config rewrite
restart_server 0 true false restart_server 0 true false
assert_equal [lindex [lindex [r module list] 0] 1] infotest set modules [lmap x [r module list] {dict get $x name}]
assert_not_equal [lsearch $modules infotest] -1
assert_equal {OK} [r module unload infotest] assert_equal {OK} [r module unload infotest]
r config rewrite r config rewrite
restart_server 0 true false restart_server 0 true false
assert_equal [llength [r module list]] 0 set modules [lmap x [r module list] {dict get $x name}]
assert_equal [lsearch $modules infotest] -1
} }
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment