diff --git a/src/Makefile b/src/Makefile index 45ee66267..a32e4c150 100644 --- a/src/Makefile +++ b/src/Makefile @@ -257,9 +257,9 @@ REDIS_SERVER_NAME=redis-server$(PROG_SUFFIX) REDIS_SENTINEL_NAME=redis-sentinel$(PROG_SUFFIX) REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o gopher.o tracking.o connection.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o REDIS_CLI_NAME=redis-cli$(PROG_SUFFIX) -REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o +REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o REDIS_BENCHMARK_NAME=redis-benchmark$(PROG_SUFFIX) -REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o release.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o +REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o release.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX) REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX) diff --git a/src/cli_common.c b/src/cli_common.c new file mode 100644 index 000000000..c45e3de96 --- /dev/null +++ b/src/cli_common.c @@ -0,0 +1,185 @@ +/* CLI (command line interface) common methods + * + * Copyright (c) 2020, Redis Labs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cli_common.h" +#include +#include +#include /* Use hiredis' sds compat header that maps sds calls to their hi_ variants */ +#include /* use sds.h from hiredis, so that only one set of sds functions will be present in the binary */ +#ifdef USE_OPENSSL +#include +#include +#include +#endif + + +/* Wrapper around redisSecureConnection to avoid hiredis_ssl dependencies if + * not building with TLS support. + */ +int cliSecureConnection(redisContext *c, cliSSLconfig config, const char **err) { +#ifdef USE_OPENSSL + static SSL_CTX *ssl_ctx = NULL; + + if (!ssl_ctx) { + ssl_ctx = SSL_CTX_new(SSLv23_client_method()); + if (!ssl_ctx) { + *err = "Failed to create SSL_CTX"; + goto error; + } + + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + + if (config.cacert || config.cacertdir) { + if (!SSL_CTX_load_verify_locations(ssl_ctx, config.cacert, config.cacertdir)) { + *err = "Invalid CA Certificate File/Directory"; + goto error; + } + } else { + if (!SSL_CTX_set_default_verify_paths(ssl_ctx)) { + *err = "Failed to use default CA paths"; + goto error; + } + } + + if (config.cert && !SSL_CTX_use_certificate_chain_file(ssl_ctx, config.cert)) { + *err = "Invalid client certificate"; + goto error; + } + + if (config.key && !SSL_CTX_use_PrivateKey_file(ssl_ctx, config.key, SSL_FILETYPE_PEM)) { + *err = "Invalid private key"; + goto error; + } + } + + SSL *ssl = SSL_new(ssl_ctx); + if (!ssl) { + *err = "Failed to create SSL object"; + return REDIS_ERR; + } + + if (config.sni && !SSL_set_tlsext_host_name(ssl, config.sni)) { + *err = "Failed to configure SNI"; + SSL_free(ssl); + return REDIS_ERR; + } + + return redisInitiateSSL(c, ssl); + +error: + SSL_CTX_free(ssl_ctx); + ssl_ctx = NULL; + return REDIS_ERR; +#else + (void) config; + (void) c; + (void) err; + return REDIS_OK; +#endif +} + +/* Wrapper around hiredis to allow arbitrary reads and writes. + * + * We piggybacks on top of hiredis to achieve transparent TLS support, + * and use its internal buffers so it can co-exist with commands + * previously/later issued on the connection. + * + * Interface is close to enough to read()/write() so things should mostly + * work transparently. + */ + +/* Write a raw buffer through a redisContext. If we already have something + * in the buffer (leftovers from hiredis operations) it will be written + * as well. + */ +ssize_t cliWriteConn(redisContext *c, const char *buf, size_t buf_len) +{ + int done = 0; + + /* Append data to buffer which is *usually* expected to be empty + * but we don't assume that, and write. + */ + c->obuf = sdscatlen(c->obuf, buf, buf_len); + if (redisBufferWrite(c, &done) == REDIS_ERR) { + if (!(c->flags & REDIS_BLOCK)) + errno = EAGAIN; + + /* On error, we assume nothing was written and we roll back the + * buffer to its original state. + */ + if (sdslen(c->obuf) > buf_len) + sdsrange(c->obuf, 0, -(buf_len+1)); + else + sdsclear(c->obuf); + + return -1; + } + + /* If we're done, free up everything. We may have written more than + * buf_len (if c->obuf was not initially empty) but we don't have to + * tell. + */ + if (done) { + sdsclear(c->obuf); + return buf_len; + } + + /* Write was successful but we have some leftovers which we should + * remove from the buffer. + * + * Do we still have data that was there prior to our buf? If so, + * restore buffer to it's original state and report no new data was + * writen. + */ + if (sdslen(c->obuf) > buf_len) { + sdsrange(c->obuf, 0, -(buf_len+1)); + return 0; + } + + /* At this point we're sure no prior data is left. We flush the buffer + * and report how much we've written. + */ + size_t left = sdslen(c->obuf); + sdsclear(c->obuf); + return buf_len - left; +} + +/* Wrapper around OpenSSL (libssl and libcrypto) initialisation + */ +int cliSecureInit() +{ +#ifdef USE_OPENSSL + ERR_load_crypto_strings(); + SSL_load_error_strings(); + SSL_library_init(); +#endif + return REDIS_OK; +} diff --git a/src/cli_common.h b/src/cli_common.h new file mode 100644 index 000000000..700a834ce --- /dev/null +++ b/src/cli_common.h @@ -0,0 +1,44 @@ +#ifndef __CLICOMMON_H +#define __CLICOMMON_H + +#include + +typedef struct cliSSLconfig { + /* Requested SNI, or NULL */ + char *sni; + /* CA Certificate file, or NULL */ + char *cacert; + /* Directory where trusted CA certificates are stored, or NULL */ + char *cacertdir; + /* Client certificate to authenticate with, or NULL */ + char *cert; + /* Private key file to authenticate with, or NULL */ + char *key; +} cliSSLconfig; + +/* Wrapper around redisSecureConnection to avoid hiredis_ssl dependencies if + * not building with TLS support. + */ +int cliSecureConnection(redisContext *c, cliSSLconfig config, const char **err); + +/* Wrapper around hiredis to allow arbitrary reads and writes. + * + * We piggybacks on top of hiredis to achieve transparent TLS support, + * and use its internal buffers so it can co-exist with commands + * previously/later issued on the connection. + * + * Interface is close to enough to read()/write() so things should mostly + * work transparently. + */ + +/* Write a raw buffer through a redisContext. If we already have something + * in the buffer (leftovers from hiredis operations) it will be written + * as well. + */ +ssize_t cliWriteConn(redisContext *c, const char *buf, size_t buf_len); + +/* Wrapper around OpenSSL (libssl and libcrypto) initialisation. + */ +int cliSecureInit(); + +#endif /* __CLICOMMON_H */ diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index 328f08077..9f27ad804 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -46,13 +46,19 @@ #include /* Use hiredis' sds compat header that maps sds calls to their hi_ variants */ #include /* Use hiredis sds. */ #include "ae.h" -#include "hiredis.h" +#include +#ifdef USE_OPENSSL +#include +#include +#include +#endif #include "adlist.h" #include "dict.h" #include "zmalloc.h" #include "atomicvar.h" #include "crc16_slottable.h" #include "hdr_histogram.h" +#include "cli_common.h" #define UNUSED(V) ((void) V) #define RANDPTR_INITIAL_SIZE 8 @@ -76,6 +82,8 @@ static struct config { const char *hostip; int hostport; const char *hostsocket; + int tls; + struct cliSSLconfig sslconfig; int numclients; redisAtomic int liveclients; int requests; @@ -280,6 +288,13 @@ static redisContext *getRedisContext(const char *ip, int port, fprintf(stderr,"%s: %s\n",hostsocket,err); goto cleanup; } + if (config.tls==1) { + const char *err = NULL; + if (cliSecureConnection(ctx, config.sslconfig, &err) == REDIS_ERR && err) { + fprintf(stderr, "Could not negotiate a TLS connection: %s\n", err); + goto cleanup; + } + } if (config.auth == NULL) return ctx; if (config.user == NULL) @@ -308,6 +323,8 @@ cleanup: return NULL; } + + static redisConfig *getRedisConfig(const char *ip, int port, const char *hostsocket) { @@ -606,19 +623,26 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) { c->start = ustime(); c->latency = -1; } - if (sdslen(c->obuf) > c->written) { + const ssize_t buflen = sdslen(c->obuf); + const ssize_t writeLen = buflen-c->written; + if (writeLen > 0) { void *ptr = c->obuf+c->written; - ssize_t nwritten = write(c->context->fd,ptr,sdslen(c->obuf)-c->written); - if (nwritten == -1) { - if (errno != EPIPE) - fprintf(stderr, "Writing to socket: %s\n", strerror(errno)); - freeClient(c); - return; - } - c->written += nwritten; - if (sdslen(c->obuf) == c->written) { - aeDeleteFileEvent(el,c->context->fd,AE_WRITABLE); - aeCreateFileEvent(el,c->context->fd,AE_READABLE,readHandler,c); + while(1) { + /* Optimistically try to write before checking if the file descriptor + * is actually writable. At worst we get EAGAIN. */ + const ssize_t nwritten = cliWriteConn(c->context,ptr,writeLen); + if (nwritten != writeLen) { + if (nwritten == -1 && errno != EAGAIN) { + if (errno != EPIPE) + fprintf(stderr, "Error writing to the server: %s\n", strerror(errno)); + freeClient(c); + return; + } + } else { + aeDeleteFileEvent(el,c->context->fd,AE_WRITABLE); + aeCreateFileEvent(el,c->context->fd,AE_READABLE,readHandler,c); + return; + } } } } @@ -680,6 +704,13 @@ static client createClient(char *cmd, size_t len, client from, int thread_id) { fprintf(stderr,"%s: %s\n",config.hostsocket,c->context->errstr); exit(1); } + if (config.tls==1) { + const char *err = NULL; + if (cliSecureConnection(c->context, config.sslconfig, &err) == REDIS_ERR && err) { + fprintf(stderr, "Could not negotiate a TLS connection: %s\n", err); + exit(1); + } + } c->thread_id = thread_id; /* Suppress hiredis cleanup of unused buffers for max speed. */ c->context->reader->maxbuf = 0; @@ -1471,6 +1502,25 @@ int parseOptions(int argc, const char **argv) { } else if (!strcmp(argv[i],"--help")) { exit_status = 0; goto usage; + #ifdef USE_OPENSSL + } else if (!strcmp(argv[i],"--tls")) { + config.tls = 1; + } else if (!strcmp(argv[i],"--sni")) { + if (lastarg) goto invalid; + config.sslconfig.sni = strdup(argv[++i]); + } else if (!strcmp(argv[i],"--cacertdir")) { + if (lastarg) goto invalid; + config.sslconfig.cacertdir = strdup(argv[++i]); + } else if (!strcmp(argv[i],"--cacert")) { + if (lastarg) goto invalid; + config.sslconfig.cacert = strdup(argv[++i]); + } else if (!strcmp(argv[i],"--cert")) { + if (lastarg) goto invalid; + config.sslconfig.cert = strdup(argv[++i]); + } else if (!strcmp(argv[i],"--key")) { + if (lastarg) goto invalid; + config.sslconfig.key = strdup(argv[++i]); + #endif } else { /* Assume the user meant to provide an option when the arg starts * with a dash. We're done otherwise and should use the remainder @@ -1518,6 +1568,16 @@ usage: " -t Only run the comma separated list of tests. The test\n" " names are the same as the ones produced as output.\n" " -I Idle mode. Just open N idle connections and wait.\n" +#ifdef USE_OPENSSL +" --tls Establish a secure TLS connection.\n" +" --sni Server name indication for TLS.\n" +" --cacert CA Certificate file to verify with.\n" +" --cacertdir Directory where trusted CA certificates are stored.\n" +" If neither cacert nor cacertdir are specified, the default\n" +" system-wide trusted root certs configuration will apply.\n" +" --cert Client certificate to authenticate with.\n" +" --key Private key file to authenticate with.\n" +#endif " --help Output this help and exit.\n" " --version Output version and exit.\n\n" "Examples:\n\n" @@ -1642,6 +1702,12 @@ int main(int argc, const char **argv) { tag = ""; +#ifdef USE_OPENSSL + if (config.tls) { + cliSecureInit(); + } +#endif + if (config.cluster_mode) { // We only include the slot placeholder {tag} if cluster mode is enabled tag = ":{tag}"; diff --git a/src/redis-cli.c b/src/redis-cli.c index 4c9e46926..50edc0c0e 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -61,6 +61,7 @@ #include "help.h" #include "anet.h" #include "ae.h" +#include "cli_common.h" #define UNUSED(V) ((void) V) @@ -199,11 +200,7 @@ static struct config { int hostport; char *hostsocket; int tls; - char *sni; - char *cacert; - char *cacertdir; - char *cert; - char *key; + cliSSLconfig sslconfig; long repeat; long interval; int dbnum; @@ -788,71 +785,6 @@ static int cliSelect(void) { return REDIS_ERR; } -/* Wrapper around redisSecureConnection to avoid hiredis_ssl dependencies if - * not building with TLS support. - */ -static int cliSecureConnection(redisContext *c, const char **err) { -#ifdef USE_OPENSSL - static SSL_CTX *ssl_ctx = NULL; - - if (!ssl_ctx) { - ssl_ctx = SSL_CTX_new(SSLv23_client_method()); - if (!ssl_ctx) { - *err = "Failed to create SSL_CTX"; - goto error; - } - - SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - - if (config.cacert || config.cacertdir) { - if (!SSL_CTX_load_verify_locations(ssl_ctx, config.cacert, config.cacertdir)) { - *err = "Invalid CA Certificate File/Directory"; - goto error; - } - } else { - if (!SSL_CTX_set_default_verify_paths(ssl_ctx)) { - *err = "Failed to use default CA paths"; - goto error; - } - } - - if (config.cert && !SSL_CTX_use_certificate_chain_file(ssl_ctx, config.cert)) { - *err = "Invalid client certificate"; - goto error; - } - - if (config.key && !SSL_CTX_use_PrivateKey_file(ssl_ctx, config.key, SSL_FILETYPE_PEM)) { - *err = "Invalid private key"; - goto error; - } - } - - SSL *ssl = SSL_new(ssl_ctx); - if (!ssl) { - *err = "Failed to create SSL object"; - return REDIS_ERR; - } - - if (config.sni && !SSL_set_tlsext_host_name(ssl, config.sni)) { - *err = "Failed to configure SNI"; - SSL_free(ssl); - return REDIS_ERR; - } - - return redisInitiateSSL(c, ssl); - -error: - SSL_CTX_free(ssl_ctx); - ssl_ctx = NULL; - return REDIS_ERR; -#else - (void) c; - (void) err; - return REDIS_OK; -#endif -} - /* Select RESP3 mode if redis-cli was started with the -3 option. */ static int cliSwitchProto(void) { redisReply *reply; @@ -886,7 +818,7 @@ static int cliConnect(int flags) { if (!context->err && config.tls) { const char *err = NULL; - if (cliSecureConnection(context, &err) == REDIS_ERR && err) { + if (cliSecureConnection(context, config.sslconfig, &err) == REDIS_ERR && err) { fprintf(stderr, "Could not negotiate a TLS connection: %s\n", err); redisFree(context); context = NULL; @@ -1484,7 +1416,7 @@ static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, .. c = redisConnect(config.hostip,config.hostport); if (!c->err && config.tls) { const char *err = NULL; - if (cliSecureConnection(c, &err) == REDIS_ERR && err) { + if (cliSecureConnection(c, config.sslconfig, &err) == REDIS_ERR && err) { fprintf(stderr, "TLS Error: %s\n", err); exit(1); } @@ -1700,15 +1632,15 @@ static int parseOptions(int argc, char **argv) { } else if (!strcmp(argv[i],"--tls")) { config.tls = 1; } else if (!strcmp(argv[i],"--sni") && !lastarg) { - config.sni = argv[++i]; + config.sslconfig.sni = argv[++i]; } else if (!strcmp(argv[i],"--cacertdir") && !lastarg) { - config.cacertdir = argv[++i]; + config.sslconfig.cacertdir = argv[++i]; } else if (!strcmp(argv[i],"--cacert") && !lastarg) { - config.cacert = argv[++i]; + config.sslconfig.cacert = argv[++i]; } else if (!strcmp(argv[i],"--cert") && !lastarg) { - config.cert = argv[++i]; + config.sslconfig.cert = argv[++i]; } else if (!strcmp(argv[i],"--key") && !lastarg) { - config.key = argv[++i]; + config.sslconfig.key = argv[++i]; #endif } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) { sds version = cliVersion(); @@ -2677,7 +2609,7 @@ static int clusterManagerNodeConnect(clusterManagerNode *node) { node->context = redisConnect(node->ip, node->port); if (!node->context->err && config.tls) { const char *err = NULL; - if (cliSecureConnection(node->context, &err) == REDIS_ERR && err) { + if (cliSecureConnection(node->context, config.sslconfig, &err) == REDIS_ERR && err) { fprintf(stderr,"TLS Error: %s\n", err); redisFree(node->context); node->context = NULL; @@ -6898,72 +6830,6 @@ void sendCapa() { sendReplconf("capa", "eof"); } -/* Wrapper around hiredis to allow arbitrary reads and writes. - * - * We piggybacks on top of hiredis to achieve transparent TLS support, - * and use its internal buffers so it can co-exist with commands - * previously/later issued on the connection. - * - * Interface is close to enough to read()/write() so things should mostly - * work transparently. - */ - -/* Write a raw buffer through a redisContext. If we already have something - * in the buffer (leftovers from hiredis operations) it will be written - * as well. - */ -static ssize_t writeConn(redisContext *c, const char *buf, size_t buf_len) -{ - int done = 0; - - /* Append data to buffer which is *usually* expected to be empty - * but we don't assume that, and write. - */ - c->obuf = sdscatlen(c->obuf, buf, buf_len); - if (redisBufferWrite(c, &done) == REDIS_ERR) { - if (!(c->flags & REDIS_BLOCK)) - errno = EAGAIN; - - /* On error, we assume nothing was written and we roll back the - * buffer to its original state. - */ - if (sdslen(c->obuf) > buf_len) - sdsrange(c->obuf, 0, -(buf_len+1)); - else - sdsclear(c->obuf); - - return -1; - } - - /* If we're done, free up everything. We may have written more than - * buf_len (if c->obuf was not initially empty) but we don't have to - * tell. - */ - if (done) { - sdsclear(c->obuf); - return buf_len; - } - - /* Write was successful but we have some leftovers which we should - * remove from the buffer. - * - * Do we still have data that was there prior to our buf? If so, - * restore buffer to it's original state and report no new data was - * writen. - */ - if (sdslen(c->obuf) > buf_len) { - sdsrange(c->obuf, 0, -(buf_len+1)); - return 0; - } - - /* At this point we're sure no prior data is left. We flush the buffer - * and report how much we've written. - */ - size_t left = sdslen(c->obuf); - sdsclear(c->obuf); - return buf_len - left; -} - /* Read raw bytes through a redisContext. The read operation is not greedy * and may not fill the buffer entirely. */ @@ -6984,7 +6850,7 @@ unsigned long long sendSync(redisContext *c, char *out_eof) { ssize_t nread; /* Send the SYNC command. */ - if (writeConn(c, "SYNC\r\n", 6) != 6) { + if (cliWriteConn(c, "SYNC\r\n", 6) != 6) { fprintf(stderr,"Error writing to master\n"); exit(1); } @@ -7249,7 +7115,7 @@ static void pipeMode(void) { while(1) { /* Transfer current buffer to server. */ if (obuf_len != 0) { - ssize_t nwritten = writeConn(context,obuf+obuf_pos,obuf_len); + ssize_t nwritten = cliWriteConn(context,obuf+obuf_pos,obuf_len); if (nwritten == -1) { if (errno != EAGAIN && errno != EINTR) { @@ -8229,9 +8095,7 @@ int main(int argc, char **argv) { #ifdef USE_OPENSSL if (config.tls) { - ERR_load_crypto_strings(); - SSL_load_error_strings(); - SSL_library_init(); + cliSecureInit(); } #endif diff --git a/tests/support/benchmark.tcl b/tests/support/benchmark.tcl index 1130c9992..ed75bfeda 100644 --- a/tests/support/benchmark.tcl +++ b/tests/support/benchmark.tcl @@ -1,5 +1,19 @@ +proc redisbenchmark_tls_config {testsdir} { + set tlsdir [file join $testsdir tls] + set cert [file join $tlsdir redis.crt] + set key [file join $tlsdir redis.key] + set cacert [file join $tlsdir ca.crt] + + if {$::tls} { + return [list --tls --cert $cert --key $key --cacert $cacert] + } else { + return {} + } +} + proc redisbenchmark {host port {opts {}}} { set cmd [list src/redis-benchmark -h $host -p $port] + lappend cmd {*}[redisbenchmark_tls_config "tests"] lappend cmd {*}$opts return $cmd }