summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorfilipe oliveira <filipecosta.90@gmail.com>2020-10-28 06:00:54 +0000
committerGitHub <noreply@github.com>2020-10-28 08:00:54 +0200
commit39436b21527d878f23eef0bd64edbff47af073c5 (patch)
tree96a6e2384a2a6aa6a66102a45e421404dc505061 /src
parent66037309c63c53a28c9553070a4557fabb84ed5a (diff)
downloadredis-39436b21527d878f23eef0bd64edbff47af073c5.tar.gz
TLS Support for redis-benchmark (#7959)
Diffstat (limited to 'src')
-rw-r--r--src/Makefile4
-rw-r--r--src/cli_common.c185
-rw-r--r--src/cli_common.h44
-rw-r--r--src/redis-benchmark.c92
-rw-r--r--src/redis-cli.c162
5 files changed, 323 insertions, 164 deletions
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 <errno.h>
+#include <hiredis.h>
+#include <sdscompat.h> /* Use hiredis' sds compat header that maps sds calls to their hi_ variants */
+#include <sds.h> /* use sds.h from hiredis, so that only one set of sds functions will be present in the binary */
+#ifdef USE_OPENSSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <hiredis_ssl.h>
+#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 <hiredis.h>
+
+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 <sdscompat.h> /* Use hiredis' sds compat header that maps sds calls to their hi_ variants */
#include <sds.h> /* Use hiredis sds. */
#include "ae.h"
-#include "hiredis.h"
+#include <hiredis.h>
+#ifdef USE_OPENSSL
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <hiredis_ssl.h>
+#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 <tests> 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 <host> Server name indication for TLS.\n"
+" --cacert <file> CA Certificate file to verify with.\n"
+" --cacertdir <dir> 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 <file> Client certificate to authenticate with.\n"
+" --key <file> 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