Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addresses #27: Adds support for making SSL connections to redis via hiredis 1.0.0+ #36

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions R/config.R
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@ redis_config <- function(..., config = list(...)) {
## 2 arg and char/int, unnamed (assume host/port?)
defaults <- list(
url = Sys_getenv("REDIS_URL", NULL),
scheme = "redis",
scheme = Sys_getenv("REDIS_CONNECTION_SCHEME", "redis"),
host = Sys_getenv("REDIS_HOST", "127.0.0.1"),
port = as.integer(Sys_getenv("REDIS_PORT", 6379L)),
path = NULL,
password = NULL,
db = NULL)
db = NULL,
CApath = Sys_getenv("REDIS_SSL_CA_PATH", NULL),
certPath = Sys_getenv("REDIS_SSL_CERT_PATH", NULL),
keyPath = Sys_getenv("REDIS_SSL_KEY_PATH", NULL))
dots <- list(...)
if (length(dots) > 0L && !identical(dots, config)) {
warning("Ignoring dots in favour of config")
Expand Down
8 changes: 8 additions & 0 deletions R/redis.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
redis_connect <- function(config) {
if (config$scheme == "redis") {
ptr <- redis_connect_tcp(config$host, config$port)
} else if (config$scheme == "rediss") {
ptr <- redis_connect_tcp_ssl(config$host, config$port, config$CApath,
config$certPath, config$keyPath)
} else {
ptr <- redis_connect_unix(config$path)
}
Expand All @@ -21,6 +24,11 @@ redis_connect_tcp <- function(host, port) {
.Call(Credux_redis_connect, host, as.integer(port))
}

redis_connect_tcp_ssl <- function(host, port, CApath, certPath, keyPath) {
.Call(Credux_redis_connect_ssl, host, as.integer(port),
CApath, certPath, keyPath)
}

redis_connect_unix <- function(path) {
.Call(Credux_redis_connect_unix, path)
}
Expand Down
7 changes: 7 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

# Library settings
PKG_CONFIG_NAME="hiredis"
PKG_CONFIG_SSL_NAME="hiredis_ssl"
PKG_DEB_NAME="libhiredis-dev"
PKG_RPM_NAME="hiredis-devel"
PKG_BREW_NAME="hiredis"
Expand All @@ -20,6 +21,12 @@ if [ $(command -v pkg-config) ]; then
PKGCONFIG_LIBS=$(pkg-config --libs ${PKG_CONFIG_NAME})
fi

# Use pkg-config to find hiredis_ssl lib if available
if [ $(command -v pkg-config) ]; then
PKGCONFIG_CFLAGS="${PKGCONFIG_CFLAGS} $(pkg-config --cflags --silence-errors ${PKG_CONFIG_SSL_NAME})"
PKGCONFIG_LIBS="${PKGCONFIG_LIBS} $(pkg-config --libs ${PKG_CONFIG_SSL_NAME})"
fi

# Note that cflags may be empty in case of success
if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then
echo "Found INCLUDE_DIR and/or LIB_DIR!"
Expand Down
2 changes: 1 addition & 1 deletion src/Makevars.win
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- makefile -*-
PKG_CPPFLAGS=-I../windows/hiredis-1.0.0/include/hiredis -DSTRICT_R_HEADERS
PKG_LIBS=-L../windows/hiredis-1.0.0/lib${R_ARCH}${CRT} -lhiredis -lws2_32
PKG_LIBS=-L../windows/hiredis-1.0.0/lib${R_ARCH}${CRT} -lhiredis -lhiredis_ssl -lssl -lcrypto -lcrypt32 -lws2_32

all: clean winlibs

Expand Down
55 changes: 55 additions & 0 deletions src/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,61 @@ SEXP redux_redis_connect(SEXP host, SEXP port) {
return extPtr;
}

SEXP redux_redis_connect_ssl(SEXP host, SEXP port, SEXP CApath,
SEXP CERTpath, SEXP KEYpath) {

// hiredis SSL connection context and error var
redisSSLContext *redis_ssl_context;
redisSSLContextError redis_ssl_error;

// Initialise OpenSSL
redisInitOpenSSL();

// Set up the SSL connection parameters
redis_ssl_context = redisCreateSSLContext(
CHAR(STRING_ELT(CApath, 0)),
NULL, /* not providing path to trusted certs */
CHAR(STRING_ELT(CERTpath, 0)),
CHAR(STRING_ELT(KEYpath, 0)),
CHAR(STRING_ELT(host, 0)),
&redis_ssl_error);

if(redis_ssl_context == NULL || redis_ssl_error != 0) {
error("Failed to create SSL context: %s\n",
(redis_ssl_error != 0) ?
redisSSLContextGetError(redis_ssl_error) : "Unknown error");
}

// Initiate a connection with redis
redisContext *context = redisConnect(CHAR(STRING_ELT(host, 0)),
INTEGER(port)[0]);
if (context == NULL) {
error("Creating context failed catastrophically [tcp_ssl]"); // # nocov
}
if (context->err != 0) {
const char * errstr = string_duplicate(context->errstr);
redisFree(context);

error("Failed to create context: %s", errstr);
}

// Now we have a connection established, we can negotiate the SSL connection
if (redisInitiateSSLWithContext(context, redis_ssl_context) != REDIS_OK) {
redisFreeSSLContext(redis_ssl_context);
if (context->err != 0) {
const char * errstr_ssl = string_duplicate(context->errstr);
redisFree(context);
error("Failed to initialize SSL connection: %s\n", errstr_ssl);
}
redisFree(context);
error("Failed to initialize SSL connection\n");
}
SEXP extPtr = PROTECT(R_MakeExternalPtr(context, host, R_NilValue));
R_RegisterCFinalizer(extPtr, redis_finalize);
UNPROTECT(1);
return extPtr;
}

SEXP redux_redis_connect_unix(SEXP path) {
redisContext *context = redisConnectUnix(CHAR(STRING_ELT(path, 0)));
if (context == NULL) {
Expand Down
3 changes: 3 additions & 0 deletions src/connection.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include <R.h>
#include <Rinternals.h>
#include <hiredis.h>
#include <hiredis_ssl.h>
#include <stdbool.h>

SEXP redux_redis_connect(SEXP host, SEXP port);
SEXP redux_redis_connect_ssl(SEXP host, SEXP port,
SEXP CApath, SEXP certPath, SEXP keyPath);
SEXP redux_redis_connect_unix(SEXP path);

SEXP redux_redis_command(SEXP extPtr, SEXP cmd);
Expand Down
1 change: 1 addition & 0 deletions src/registration.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

static const R_CallMethodDef callMethods[] = {
{"Credux_redis_connect", (DL_FUNC) &redux_redis_connect, 2},
{"Credux_redis_connect_ssl", (DL_FUNC) &redux_redis_connect_ssl, 5},
{"Credux_redis_connect_unix", (DL_FUNC) &redux_redis_connect_unix, 1},

{"Credux_redis_command", (DL_FUNC) &redux_redis_command, 2},
Expand Down