Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64da57e0c7 | ||
|
|
91717bd15c | ||
|
|
f12d52c1ed |
@ -11,6 +11,11 @@ MACRO(getVersionBit name)
|
|||||||
STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}")
|
STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}")
|
||||||
ENDMACRO(getVersionBit)
|
ENDMACRO(getVersionBit)
|
||||||
|
|
||||||
|
IF (${CMAKE_C_COMPILER_ID} MATCHES "GNU" OR ${CMAKE_C_COMPILER_ID} MATCHES "Clang")
|
||||||
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||||
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
getVersionBit(HIREDIS_MAJOR)
|
getVersionBit(HIREDIS_MAJOR)
|
||||||
getVersionBit(HIREDIS_MINOR)
|
getVersionBit(HIREDIS_MINOR)
|
||||||
getVersionBit(HIREDIS_PATCH)
|
getVersionBit(HIREDIS_PATCH)
|
||||||
@ -75,3 +80,8 @@ ENDIF()
|
|||||||
IF(ENABLE_EXAMPLES)
|
IF(ENABLE_EXAMPLES)
|
||||||
ADD_SUBDIRECTORY(examples)
|
ADD_SUBDIRECTORY(examples)
|
||||||
ENDIF(ENABLE_EXAMPLES)
|
ENDIF(ENABLE_EXAMPLES)
|
||||||
|
|
||||||
|
IF(ENABLE_TESTS)
|
||||||
|
ADD_SUBDIRECTORY(contrib/gtest)
|
||||||
|
ADD_SUBDIRECTORY(cpptests)
|
||||||
|
ENDIF()
|
||||||
17
cpptests/CMakeLists.txt
Normal file
17
cpptests/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
INCLUDE(CTest)
|
||||||
|
INCLUDE_DIRECTORIES(${gtest_SOURCE_DIR}/include)
|
||||||
|
INCLUDE_DIRECTORIES(PROJECT_SOURCE_DIR)
|
||||||
|
INCLUDE_DIRECTORIES(${LIBEVENT_INCLUDES})
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(hiredis-gtest t_basic.cpp t_client.cpp t_async.cpp
|
||||||
|
common.cpp main.cpp)
|
||||||
|
TARGET_LINK_LIBRARIES(hiredis-gtest gtest hiredis event)
|
||||||
|
ADD_TEST(NAME hiredis-test COMMAND hiredis-test)
|
||||||
|
SET_PROPERTY(TARGET hiredis-gtest PROPERTY CXX_STANDARD 11)
|
||||||
|
|
||||||
|
SET(EXAMPLE_CERT "${CMAKE_CURRENT_SOURCE_DIR}/example.crt")
|
||||||
|
SET(EXAMPLE_KEY "${CMAKE_CURRENT_SOURCE_DIR}/example.key")
|
||||||
|
|
||||||
|
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL_CA="${EXAMPLE_CERT}")
|
||||||
|
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL_KEY="${EXAMPLE_KEY}")
|
||||||
|
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL_CERT="${EXAMPLE_CERT}")
|
||||||
106
cpptests/common.cpp
Normal file
106
cpptests/common.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
hiredis::ClientSettings hiredis::settings_g;
|
||||||
|
|
||||||
|
using namespace hiredis;
|
||||||
|
|
||||||
|
void ClientSettings::setHost(const char *s) {
|
||||||
|
m_mode = REDIS_CONN_TCP;
|
||||||
|
std::string hostval(s);
|
||||||
|
size_t idx = hostval.find(':');
|
||||||
|
if (idx == std::string::npos) {
|
||||||
|
// First part is hostname only
|
||||||
|
m_hostname = hostval;
|
||||||
|
} else {
|
||||||
|
m_port = atoi(hostval.c_str() + idx + 1);
|
||||||
|
hostval.resize(idx);
|
||||||
|
}
|
||||||
|
if (!m_port) {
|
||||||
|
m_port = 6379;
|
||||||
|
}
|
||||||
|
m_hostname = hostval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSettings::setUnix(const char *s) {
|
||||||
|
m_mode = REDIS_CONN_UNIX;
|
||||||
|
m_hostname = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSettings::applyEnv() {
|
||||||
|
std::string hostval;
|
||||||
|
if (getenv("REDIS_SOCKET")) {
|
||||||
|
m_hostname.assign(getenv("REDIS_SOCKET"));
|
||||||
|
m_mode = REDIS_CONN_UNIX;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getenv("REDIS_HOST")) {
|
||||||
|
setHost(getenv("REDIS_HOST"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle SSL settings as well
|
||||||
|
if (getenv("REDIS_SSL_CLIENT_CERT")) {
|
||||||
|
m_ssl_cert_path = getenv("REDIS_SSL_CLIENT_CERT");
|
||||||
|
}
|
||||||
|
if (getenv("REDIS_SSL_CLIENT_KEY")) {
|
||||||
|
m_ssl_key_path = getenv("REDIS_SSL_CLIENT_KEY");
|
||||||
|
}
|
||||||
|
if (getenv("REDIS_SSL_CA")) {
|
||||||
|
m_ssl_ca_path = getenv("REDIS_SSL_CA");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientSettings::initOptions(redisOptions& options) const {
|
||||||
|
if (m_mode == REDIS_CONN_TCP) {
|
||||||
|
REDIS_OPTIONS_SET_TCP(&options, hostname(), port());
|
||||||
|
} else if (options.type == REDIS_CONN_UNIX) {
|
||||||
|
REDIS_OPTIONS_SET_UNIX(&options, hostname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ConnectError::ConnectError(const redisOptions& options) {
|
||||||
|
if (options.type == REDIS_CONN_TCP) {
|
||||||
|
endpoint = options.endpoint.tcp.ip;
|
||||||
|
endpoint += ":";
|
||||||
|
endpoint += options.endpoint.tcp.port;
|
||||||
|
} else if (options.type == REDIS_CONN_UNIX) {
|
||||||
|
endpoint = "unix://";
|
||||||
|
endpoint += options.endpoint.unix_socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientError::throwCode(int code) {
|
||||||
|
switch (code) {
|
||||||
|
case REDIS_ERR_IO:
|
||||||
|
throw IOError();
|
||||||
|
case REDIS_ERR_EOF:
|
||||||
|
throw IOError("EOF");
|
||||||
|
case REDIS_ERR_PROTOCOL:
|
||||||
|
throw IOError("Protocol Error");
|
||||||
|
case REDIS_ERR_TIMEOUT:
|
||||||
|
throw TimeoutError();
|
||||||
|
default: {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "unknown error code: ";
|
||||||
|
ss << code;
|
||||||
|
throw ClientError(ss.str().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientError::throwContext(const redisContext *c) {
|
||||||
|
const char *s;
|
||||||
|
switch (c->err) {
|
||||||
|
case REDIS_ERR_IO:
|
||||||
|
case REDIS_ERR_EOF:
|
||||||
|
case REDIS_ERR_PROTOCOL:
|
||||||
|
throw IOError(c->errstr);
|
||||||
|
case REDIS_ERR_TIMEOUT:
|
||||||
|
throw TimeoutError();
|
||||||
|
default:
|
||||||
|
throw ClientError(c->errstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
105
cpptests/common.h
Normal file
105
cpptests/common.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#ifndef HIREDIS_CPP_COMMON_H
|
||||||
|
#define HIREDIS_CPP_COMMON_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include "hiredis.h"
|
||||||
|
|
||||||
|
namespace hiredis {
|
||||||
|
class ClientSettings {
|
||||||
|
public:
|
||||||
|
void applyEnv();
|
||||||
|
void setHost(const char *s);
|
||||||
|
void setUnix(const char *s);
|
||||||
|
void setSsl(bool v) { m_ssl_enabled = v; }
|
||||||
|
|
||||||
|
const char *ssl_cert() const { return m_ssl_cert_path; }
|
||||||
|
const char *ssl_key() const { return m_ssl_key_path; }
|
||||||
|
const char *ssl_ca() const { return m_ssl_ca_path; }
|
||||||
|
|
||||||
|
bool is_ssl() const {
|
||||||
|
return m_ssl_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_unix() const {
|
||||||
|
return m_mode == REDIS_CONN_UNIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *hostname() const {
|
||||||
|
return m_hostname.c_str();
|
||||||
|
}
|
||||||
|
uint16_t port() const {
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
int mode() const {
|
||||||
|
return m_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initOptions(redisOptions& options) const;
|
||||||
|
|
||||||
|
std::string m_hostname = "localhost";
|
||||||
|
uint16_t m_port = 6379;
|
||||||
|
|
||||||
|
int m_mode = REDIS_CONN_TCP;
|
||||||
|
const char *m_ssl_cert_path = NULL;
|
||||||
|
const char *m_ssl_ca_path = NULL;
|
||||||
|
const char *m_ssl_key_path = NULL;
|
||||||
|
bool m_ssl_enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ClientSettings settings_g;
|
||||||
|
|
||||||
|
class ClientError : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
ClientError() : std::runtime_error("hiredis error") {
|
||||||
|
}
|
||||||
|
ClientError(const char *s) : std::runtime_error(s) {
|
||||||
|
}
|
||||||
|
static void throwCode(int code);
|
||||||
|
static void throwContext(const redisContext *ac);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectError : public ClientError {
|
||||||
|
public:
|
||||||
|
ConnectError() : ClientError(){}
|
||||||
|
ConnectError(const redisOptions& options);
|
||||||
|
virtual const char *what() const noexcept override{
|
||||||
|
return endpoint.c_str();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string endpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IOError : public ClientError {
|
||||||
|
public:
|
||||||
|
IOError() : ClientError(){}
|
||||||
|
IOError(const char *s) : ClientError(s) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TimeoutError : public ClientError {
|
||||||
|
public:
|
||||||
|
TimeoutError() : ClientError("timed out") {}
|
||||||
|
TimeoutError(const char *s) : ClientError(s) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SSLError : public ClientError {
|
||||||
|
public:
|
||||||
|
SSLError() : ClientError() {}
|
||||||
|
SSLError(const char *what) : ClientError(what) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandError : public ClientError {
|
||||||
|
public:
|
||||||
|
CommandError(const redisReply *r) {
|
||||||
|
errstr = r->str;
|
||||||
|
}
|
||||||
|
virtual const char *what() const noexcept override {
|
||||||
|
return errstr.c_str();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string errstr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
30
cpptests/example.crt
Normal file
30
cpptests/example.crt
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
LPKxSkVpeDRSDNFyYYUOTY4BJVbwnxy5Kto=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
51
cpptests/example.key
Normal file
51
cpptests/example.key
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
50
cpptests/main.cpp
Normal file
50
cpptests/main.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <tuple>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
using namespace hiredis;
|
||||||
|
|
||||||
|
static std::string getKvValue(const std::string& s) {
|
||||||
|
size_t n = s.find('=');
|
||||||
|
if (n == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return s.substr(n+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isArg(const char *arg, const char *s) {
|
||||||
|
return strncasecmp(arg, s, strlen(s)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
ClientSettings* settings = &settings_g;
|
||||||
|
|
||||||
|
#ifdef HIREDIS_TEST_SSL_CA
|
||||||
|
printf("Setting SSL compile time defaults\n");
|
||||||
|
settings->m_ssl_ca_path = HIREDIS_TEST_SSL_CA;
|
||||||
|
settings->m_ssl_cert_path = HIREDIS_TEST_SSL_CERT;
|
||||||
|
settings->m_ssl_key_path = HIREDIS_TEST_SSL_KEY;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (size_t ii = 1; ii < argc; ++ii) {
|
||||||
|
const char *ss = argv[ii];
|
||||||
|
if (isArg(ss, "--unix")) {
|
||||||
|
settings->setUnix(getKvValue(ss).c_str());
|
||||||
|
} else if (isArg(ss, "--host")) {
|
||||||
|
settings->setHost(getKvValue(ss).c_str());
|
||||||
|
printf("Set host to %s:%u\n", settings->m_hostname.c_str(), settings->m_port);
|
||||||
|
} else if (isArg(ss, "--ssl")) {
|
||||||
|
auto v = getKvValue(ss);
|
||||||
|
if (v == "0" || v == "false") {
|
||||||
|
settings->setSsl(false);
|
||||||
|
} else {
|
||||||
|
printf("enabling ssl for tests\n");
|
||||||
|
settings->setSsl(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
3
cpptests/run_test.py
Normal file
3
cpptests/run_test.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
128
cpptests/stunnel.conf
Normal file
128
cpptests/stunnel.conf
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
; Sample stunnel configuration file for Unix by Michal Trojnara 1998-2018
|
||||||
|
; Some options used here may be inadequate for your particular configuration
|
||||||
|
; This sample file does *not* represent stunnel.conf defaults
|
||||||
|
; Please consult the manual for detailed description of available options
|
||||||
|
|
||||||
|
; **************************************************************************
|
||||||
|
; * Global options *
|
||||||
|
; **************************************************************************
|
||||||
|
|
||||||
|
; It is recommended to drop root privileges if stunnel is started by root
|
||||||
|
;setuid = nobody
|
||||||
|
;setgid = nogroup
|
||||||
|
|
||||||
|
; PID file is created inside the chroot jail (if enabled)
|
||||||
|
;pid = /usr/local/var/run/stunnel.pid
|
||||||
|
|
||||||
|
; Debugging stuff (may be useful for troubleshooting)
|
||||||
|
foreground = yes
|
||||||
|
debug = debug
|
||||||
|
;output = /usr/local/var/log/stunnel.log
|
||||||
|
|
||||||
|
; Enable FIPS 140-2 mode if needed for compliance
|
||||||
|
;fips = yes
|
||||||
|
|
||||||
|
; The pkcs11 engine allows for authentication with cryptographic
|
||||||
|
; keys isolated in a hardware or software token
|
||||||
|
; MODULE_PATH specifies the path to the pkcs11 module shared library,
|
||||||
|
; e.g. softhsm2.dll or opensc-pkcs11.so
|
||||||
|
; Each section using this feature also needs the "engineId = pkcs11" option
|
||||||
|
;engine = pkcs11
|
||||||
|
;engineCtrl = MODULE_PATH:/usr/lib/softhsm/libsofthsm2.so
|
||||||
|
;engineCtrl = PIN:1234
|
||||||
|
|
||||||
|
; **************************************************************************
|
||||||
|
; * Service defaults may also be specified in individual service sections *
|
||||||
|
; **************************************************************************
|
||||||
|
|
||||||
|
; Enable support for the insecure SSLv3 protocol
|
||||||
|
delay = yes
|
||||||
|
options = NO_SSLv3
|
||||||
|
options = NO_TLSv1
|
||||||
|
options = CIPHER_SERVER_PREFERENCE
|
||||||
|
options = DONT_INSERT_EMPTY_FRAGMENTS
|
||||||
|
|
||||||
|
|
||||||
|
; These options provide additional security at some performance degradation
|
||||||
|
;options = SINGLE_ECDH_USE
|
||||||
|
;options = SINGLE_DH_USE
|
||||||
|
|
||||||
|
; **************************************************************************
|
||||||
|
; * Include all configuration file fragments from the specified folder *
|
||||||
|
; **************************************************************************
|
||||||
|
|
||||||
|
;include = /usr/local/etc/stunnel/conf.d
|
||||||
|
|
||||||
|
; **************************************************************************
|
||||||
|
; * Service definitions (remove all services for inetd mode) *
|
||||||
|
; **************************************************************************
|
||||||
|
|
||||||
|
; ***************************************** Example TLS client mode services
|
||||||
|
|
||||||
|
; The following examples use /etc/ssl/certs, which is the common location
|
||||||
|
; of a hashed directory containing trusted CA certificates. This is not
|
||||||
|
; a hardcoded path of the stunnel package, as it is not related to the
|
||||||
|
; stunnel configuration in /usr/local/etc/stunnel/.
|
||||||
|
|
||||||
|
[redis]
|
||||||
|
;client = yes
|
||||||
|
accept = 16379
|
||||||
|
connect = 6379
|
||||||
|
cert = example.crt
|
||||||
|
key = example.key
|
||||||
|
|
||||||
|
; Encrypted HTTP proxy authenticated with a client certificate
|
||||||
|
; located in a cryptographic token
|
||||||
|
;[example-pkcs11]
|
||||||
|
;client = yes
|
||||||
|
;accept = 127.0.0.1:8080
|
||||||
|
;connect = example.com:8443
|
||||||
|
;engineId = pkcs11
|
||||||
|
;cert = pkcs11:token=MyToken;object=MyCert
|
||||||
|
;key = pkcs11:token=MyToken;object=MyKey
|
||||||
|
|
||||||
|
; ***************************************** Example TLS server mode services
|
||||||
|
|
||||||
|
;[pop3s]
|
||||||
|
;accept = 995
|
||||||
|
;connect = 110
|
||||||
|
;cert = /usr/local/etc/stunnel/stunnel.pem
|
||||||
|
|
||||||
|
;[imaps]
|
||||||
|
;accept = 993
|
||||||
|
;connect = 143
|
||||||
|
;cert = /usr/local/etc/stunnel/stunnel.pem
|
||||||
|
|
||||||
|
; Either only expose this service to trusted networks, or require
|
||||||
|
; authentication when relaying emails originated from loopback.
|
||||||
|
; Otherwise the following configuration creates an open relay.
|
||||||
|
;[ssmtp]
|
||||||
|
;accept = 465
|
||||||
|
;connect = 25
|
||||||
|
;cert = /usr/local/etc/stunnel/stunnel.pem
|
||||||
|
|
||||||
|
; TLS front-end to a web server
|
||||||
|
;[https]
|
||||||
|
;accept = 443
|
||||||
|
;connect = 80
|
||||||
|
;cert = /usr/local/etc/stunnel/stunnel.pem
|
||||||
|
; "TIMEOUTclose = 0" is a workaround for a design flaw in Microsoft SChannel
|
||||||
|
; Microsoft implementations do not use TLS close-notify alert and thus they
|
||||||
|
; are vulnerable to truncation attacks
|
||||||
|
;TIMEOUTclose = 0
|
||||||
|
|
||||||
|
; Remote shell protected with PSK-authenticated TLS
|
||||||
|
; Create "/usr/local/etc/stunnel/secrets.txt" containing IDENTITY:KEY pairs
|
||||||
|
;[shell]
|
||||||
|
;accept = 1337
|
||||||
|
;exec = /bin/sh
|
||||||
|
;execArgs = sh -i
|
||||||
|
;PSKsecrets = /usr/local/etc/stunnel/secrets.txt
|
||||||
|
|
||||||
|
; Non-standard MySQL-over-TLS encapsulation connecting the Unix socket
|
||||||
|
;[mysql]
|
||||||
|
;cert = /usr/local/etc/stunnel/stunnel.pem
|
||||||
|
;accept = 3307
|
||||||
|
;connect = /run/mysqld/mysqld.sock
|
||||||
|
|
||||||
|
; vim:ft=dosini
|
||||||
164
cpptests/t_async.cpp
Normal file
164
cpptests/t_async.cpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <hiredis.h>
|
||||||
|
#include "adapters/libevent.h"
|
||||||
|
#include <functional>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
using namespace hiredis;
|
||||||
|
|
||||||
|
struct AsyncClient;
|
||||||
|
typedef std::function<void(AsyncClient*, bool)> ConnectionCallback;
|
||||||
|
typedef std::function<void(AsyncClient*, bool)> DisconnectCallback;
|
||||||
|
typedef std::function<void(AsyncClient*, redisReply *)> CommandCallback;
|
||||||
|
|
||||||
|
static void realConnectCb(const redisAsyncContext*, int);
|
||||||
|
static void realDisconnectCb(const redisAsyncContext*, int);
|
||||||
|
static void realCommandCb(redisAsyncContext*, void*, void*);
|
||||||
|
|
||||||
|
struct CmdData {
|
||||||
|
AsyncClient *client;
|
||||||
|
CommandCallback cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AsyncClient {
|
||||||
|
void connectCommon(const redisOptions& orig, event_base *b, unsigned timeoutMs) {
|
||||||
|
redisOptions options = orig;
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
if (timeoutMs) {
|
||||||
|
tv.tv_usec = timeoutMs * 1000;
|
||||||
|
options.timeout = &tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ac = redisAsyncConnectWithOptions(&options);
|
||||||
|
ac->data = this;
|
||||||
|
redisLibeventAttach(ac, b);
|
||||||
|
redisAsyncSetConnectCallback(ac, realConnectCb);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncClient(const redisOptions& options, event_base* b, unsigned timeoutMs = 0) {
|
||||||
|
connectCommon(options, b, timeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncClient(const ClientSettings& settings, event_base *b, unsigned timeoutMs = 0) {
|
||||||
|
redisOptions options = { 0 };
|
||||||
|
settings.initOptions(options);
|
||||||
|
connectCommon(options, b, timeoutMs);
|
||||||
|
|
||||||
|
if (ac->c.err != REDIS_OK) {
|
||||||
|
ClientError::throwContext(&ac->c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.is_ssl()) {
|
||||||
|
printf("Securing async connection...\n");
|
||||||
|
int rc = redisSecureConnection(&ac->c,
|
||||||
|
settings.ssl_ca(), settings.ssl_cert(), settings.ssl_key(),
|
||||||
|
NULL);
|
||||||
|
if (rc != REDIS_OK) {
|
||||||
|
throw SSLError(ac->c.errstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncClient(redisAsyncContext *ac) : ac(ac) {
|
||||||
|
redisAsyncSetDisconnectCallback(ac, realDisconnectCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onConnect(ConnectionCallback cb) {
|
||||||
|
conncb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncClient() {
|
||||||
|
if (ac != NULL) {
|
||||||
|
auto tmpac = ac;
|
||||||
|
ac = NULL;
|
||||||
|
redisAsyncDisconnect(tmpac);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd(CommandCallback cb, const char *fmt, ...) {
|
||||||
|
auto data = new CmdData {this, cb };
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
redisvAsyncCommand(ac, realCommandCb, data, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnect(DisconnectCallback cb) {
|
||||||
|
disconncb = cb;
|
||||||
|
auto tmpac = ac;
|
||||||
|
ac = NULL;
|
||||||
|
redisAsyncDisconnect(tmpac);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnect() {
|
||||||
|
auto tmpac = ac;
|
||||||
|
ac = NULL;
|
||||||
|
redisAsyncDisconnect(tmpac);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionCallback conncb;
|
||||||
|
DisconnectCallback disconncb;
|
||||||
|
redisAsyncContext *ac;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void realConnectCb(const redisAsyncContext *ac, int status) {
|
||||||
|
auto self = reinterpret_cast<AsyncClient*>(ac->data);
|
||||||
|
if (self->conncb) {
|
||||||
|
self->conncb(self, status == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void realDisconnectCb(const redisAsyncContext *ac, int status) {
|
||||||
|
auto self = reinterpret_cast<AsyncClient*>(ac->data);
|
||||||
|
if (self->disconncb) {
|
||||||
|
self->disconncb(self, status == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void realCommandCb(redisAsyncContext *ac, void *r, void *ctx) {
|
||||||
|
auto *d = reinterpret_cast<CmdData*>(ctx);
|
||||||
|
auto *rep = reinterpret_cast<redisReply*>(r);
|
||||||
|
auto *self = reinterpret_cast<AsyncClient*>(ac->data);
|
||||||
|
d->cb(self, rep);
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsyncTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
libevent = event_base_new();
|
||||||
|
}
|
||||||
|
void TearDown() override {
|
||||||
|
event_base_free(libevent);
|
||||||
|
libevent = NULL;
|
||||||
|
}
|
||||||
|
void wait() {
|
||||||
|
event_base_dispatch(libevent);
|
||||||
|
}
|
||||||
|
event_base *libevent;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(AsyncTest, testAsync) {
|
||||||
|
AsyncClient client(settings_g, libevent, 1000);
|
||||||
|
|
||||||
|
bool gotConnect = false;
|
||||||
|
bool gotCommand = false;
|
||||||
|
client.onConnect([&](AsyncClient*, bool status) {
|
||||||
|
ASSERT_TRUE(status);
|
||||||
|
gotConnect = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
client.cmd([&](AsyncClient *c, redisReply *r) {
|
||||||
|
ASSERT_TRUE(r != NULL);
|
||||||
|
ASSERT_EQ(REDIS_REPLY_STATUS, r->type);
|
||||||
|
ASSERT_STREQ("PONG", r->str);
|
||||||
|
c->disconnect();
|
||||||
|
gotCommand = true;
|
||||||
|
}, "PING");
|
||||||
|
wait();
|
||||||
|
|
||||||
|
ASSERT_TRUE(gotConnect);
|
||||||
|
ASSERT_TRUE(gotCommand);
|
||||||
|
}
|
||||||
34
cpptests/t_basic.cpp
Normal file
34
cpptests/t_basic.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include "hiredis.h"
|
||||||
|
|
||||||
|
class FormatterTest : public ::testing::Test {
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static std::string formatCommand(const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
char *s = NULL;
|
||||||
|
size_t n = redisvFormatCommand(&s, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
std::string xs(s, n);
|
||||||
|
free(s);
|
||||||
|
return xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FormatterTest, testFormatCommands) {
|
||||||
|
auto expected = "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n";
|
||||||
|
ASSERT_EQ(expected, formatCommand("SET foo bar"))
|
||||||
|
<< "No interpolation";
|
||||||
|
|
||||||
|
expected = "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n";
|
||||||
|
ASSERT_EQ(expected, formatCommand("SET %s %s", "foo", "bar"))
|
||||||
|
<< "interpolation";
|
||||||
|
|
||||||
|
expected = "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n";
|
||||||
|
ASSERT_EQ(expected, formatCommand("SET %s %s", "foo", ""))
|
||||||
|
<< "empty string";
|
||||||
|
}
|
||||||
112
cpptests/t_client.cpp
Normal file
112
cpptests/t_client.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
#include "hiredis.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace hiredis;
|
||||||
|
|
||||||
|
class Client {
|
||||||
|
public:
|
||||||
|
operator redisContext*() {
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client(redisContext *ctx) :ctx(ctx) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Client(const redisOptions& options) {
|
||||||
|
connectOrThrow(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
Client(const ClientSettings& settings) {
|
||||||
|
redisOptions options = {0};
|
||||||
|
settings.initOptions(options);
|
||||||
|
connectOrThrow(options);
|
||||||
|
if (settings.is_ssl()) {
|
||||||
|
secureConnection(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void secureConnection(const ClientSettings& settings) {
|
||||||
|
if (redisSecureConnection(
|
||||||
|
ctx, settings.ssl_ca(), settings.ssl_cert(),
|
||||||
|
settings.ssl_key(), NULL) != REDIS_OK) {
|
||||||
|
redisFree(ctx);
|
||||||
|
ctx = NULL;
|
||||||
|
throw SSLError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redisReply *cmd(const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
void *p = redisvCommand(ctx, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return reinterpret_cast<redisReply*>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flushdb() {
|
||||||
|
redisReply *p = cmd("FLUSHDB");
|
||||||
|
if (p == NULL) {
|
||||||
|
ClientError::throwCode(ctx->err);
|
||||||
|
}
|
||||||
|
if (p->type == REDIS_REPLY_ERROR) {
|
||||||
|
auto pp = CommandError(p);
|
||||||
|
freeReplyObject(p);
|
||||||
|
throw pp;
|
||||||
|
}
|
||||||
|
freeReplyObject(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Client() {
|
||||||
|
if (ctx != NULL) {
|
||||||
|
redisFree(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Client(Client&& other) {
|
||||||
|
this->ctx = other.ctx;
|
||||||
|
other.ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nothing() const {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void destroyAndThrow() {
|
||||||
|
assert(ctx->err);
|
||||||
|
int err = ctx->err;
|
||||||
|
redisFree(ctx);
|
||||||
|
ctx = NULL;
|
||||||
|
ClientError::throwCode(err);
|
||||||
|
}
|
||||||
|
void connectOrThrow(const redisOptions& options) {
|
||||||
|
ctx = redisConnectWithOptions(&options);
|
||||||
|
if (!ctx) {
|
||||||
|
throw ConnectError();
|
||||||
|
}
|
||||||
|
if (ctx->err) {
|
||||||
|
destroyAndThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
redisContext *ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClientTest : public ::testing::Test {
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(ClientTest, testTimeout) {
|
||||||
|
redisOptions options = {0};
|
||||||
|
timeval tv = {0};
|
||||||
|
tv.tv_usec = 10000; // 10k micros, small enough
|
||||||
|
options.timeout = &tv;
|
||||||
|
// see https://tools.ietf.org/html/rfc5737
|
||||||
|
// this block of addresses is reserved for "documentation", and it
|
||||||
|
// would likely not connect, ever.
|
||||||
|
ASSERT_THROW(Client(options).nothing(), ClientError);
|
||||||
|
|
||||||
|
// Test the normal timeout
|
||||||
|
Client c(settings_g);
|
||||||
|
c.flushdb();
|
||||||
|
}
|
||||||
23
get_gtest.sh
Executable file
23
get_gtest.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Run this from the toplevel directory of the source code tree
|
||||||
|
GTEST_URL_BASE=https://s3-eu-central-1.amazonaws.com/redislabs-dev-public-deps
|
||||||
|
GTEST_URL_BASE=https://github.com/google/googletest/archive/
|
||||||
|
GTEST_FILENAME=release-1.8.0.tar.gz
|
||||||
|
GTEST_TOPDIR=googletest-release-1.8.0
|
||||||
|
DESTDIR=contrib
|
||||||
|
|
||||||
|
if [ -d $DESTDIR/gtest ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
curdir=$PWD
|
||||||
|
tarball=/tmp/${GTEST_FILENAME}
|
||||||
|
url=${GTEST_URL_BASE}/${GTEST_FILENAME}
|
||||||
|
if [ ! -e $tarball ]; then
|
||||||
|
wget -O $tarball $url
|
||||||
|
fi
|
||||||
|
|
||||||
|
tar -C $DESTDIR -xf $tarball
|
||||||
|
rm $DESTDIR/gtest
|
||||||
|
cd $DESTDIR
|
||||||
|
ln -s $GTEST_TOPDIR gtest
|
||||||
@ -685,7 +685,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
|
||||||
redisContextSetTimeout(c, *options->timeout);
|
if (!(options->options & REDIS_OPT_NORDWRTIMEOUT)) {
|
||||||
|
redisContextSetTimeout(c, *options->timeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -703,6 +705,7 @@ redisContext *redisConnectWithTimeout(const char *ip, int port, const struct tim
|
|||||||
redisOptions options = {0};
|
redisOptions options = {0};
|
||||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||||
options.timeout = &tv;
|
options.timeout = &tv;
|
||||||
|
options.options |= REDIS_OPT_NORDWRTIMEOUT;
|
||||||
return redisConnectWithOptions(&options);
|
return redisConnectWithOptions(&options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -133,6 +133,13 @@ struct redisSsl;
|
|||||||
*/
|
*/
|
||||||
#define REDIS_OPT_NOAUTOFREE 0x04
|
#define REDIS_OPT_NOAUTOFREE 0x04
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When using connectWithOptions, have the timeout only apply to the
|
||||||
|
* initial connect, not subsequent read/write attempts. This option
|
||||||
|
* is here to support the legacy connectWithTimeout()
|
||||||
|
*/
|
||||||
|
#define REDIS_OPT_NORDWRTIMEOUT 0x08
|
||||||
|
|
||||||
/* In Unix systems a file descriptor is a regular signed int, with -1
|
/* In Unix systems a file descriptor is a regular signed int, with -1
|
||||||
* representing an invalid descriptor. In Windows it is a SOCKET
|
* representing an invalid descriptor. In Windows it is a SOCKET
|
||||||
* (32- or 64-bit unsigned integer depending on the architecture), where
|
* (32- or 64-bit unsigned integer depending on the architecture), where
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user