summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--fmacros.h4
-rw-r--r--hiredis.c7
-rw-r--r--hiredis.h3
-rw-r--r--net.c40
-rw-r--r--net.h1
-rw-r--r--test.c27
7 files changed, 83 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a57b81..268b15c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
### 0.11.0
-* Increase the maximum multi-bulk reply depth to 8.
+* Increase the maximum multi-bulk reply depth to 7.
* Increase the read buffer size from 2k to 16k.
diff --git a/fmacros.h b/fmacros.h
index 21cd9cf..799c12c 100644
--- a/fmacros.h
+++ b/fmacros.h
@@ -13,4 +13,8 @@
#define _XOPEN_SOURCE
#endif
+#if __APPLE__ && __MACH__
+#define _OSX
+#endif
+
#endif
diff --git a/hiredis.c b/hiredis.c
index 958f58b..84baa8c 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -1092,6 +1092,13 @@ int redisSetTimeout(redisContext *c, struct timeval tv) {
return REDIS_ERR;
}
+/* Enable connection KeepAlive. */
+int redisEnableKeepAlive(redisContext *c) {
+ if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
+ return REDIS_ERR;
+ return REDIS_OK;
+}
+
/* Use this function to handle a read event on the descriptor. It will try
* and read some bytes from the socket and feed them to the reply parser.
*
diff --git a/hiredis.h b/hiredis.h
index aadcf35..42290a1 100644
--- a/hiredis.h
+++ b/hiredis.h
@@ -88,6 +88,8 @@
#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */
+#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -177,6 +179,7 @@ redisContext *redisConnectUnix(const char *path);
redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv);
redisContext *redisConnectUnixNonBlock(const char *path);
int redisSetTimeout(redisContext *c, struct timeval tv);
+int redisEnableKeepAlive(redisContext *c);
void redisFree(redisContext *c);
int redisBufferRead(redisContext *c);
int redisBufferWrite(redisContext *c, int *done);
diff --git a/net.c b/net.c
index 82ab2b4..3c07d68 100644
--- a/net.c
+++ b/net.c
@@ -113,6 +113,45 @@ static int redisSetBlocking(redisContext *c, int fd, int blocking) {
return REDIS_OK;
}
+int redisKeepAlive(redisContext *c, int interval) {
+ int val = 1;
+ int fd = c->fd;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
+ __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
+ return REDIS_ERR;
+ }
+
+#ifdef _OSX
+ val = interval;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
+ __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
+ return REDIS_ERR;
+ }
+#else
+ val = interval;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
+ __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
+ return REDIS_ERR;
+ }
+
+ val = interval/3;
+ if (val == 0) val = 1;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
+ __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
+ return REDIS_ERR;
+ }
+
+ val = 3;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
+ __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
+ return REDIS_ERR;
+ }
+#endif
+
+ return REDIS_OK;
+}
+
static int redisSetTcpNoDelay(redisContext *c, int fd) {
int yes = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
@@ -136,6 +175,7 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
/* Only use timeout when not NULL. */
if (timeout != NULL) {
if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
+ __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
close(fd);
return REDIS_ERR;
}
diff --git a/net.h b/net.h
index eb8a0a1..36096fe 100644
--- a/net.h
+++ b/net.h
@@ -43,5 +43,6 @@ int redisCheckSocketError(redisContext *c, int fd);
int redisContextSetTimeout(redisContext *c, struct timeval tv);
int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout);
int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *timeout);
+int redisKeepAlive(redisContext *c, int interval);
#endif
diff --git a/test.c b/test.c
index 47197fd..6599014 100644
--- a/test.c
+++ b/test.c
@@ -8,6 +8,7 @@
#include <unistd.h>
#include <signal.h>
#include <errno.h>
+#include <limits.h>
#include "hiredis.h"
@@ -22,6 +23,7 @@ struct config {
struct {
const char *host;
int port;
+ struct timeval timeout;
} tcp;
struct {
@@ -435,6 +437,30 @@ static void test_blocking_io_errors(struct config config) {
redisFree(c);
}
+static void test_invalid_timeout_errors(struct config config) {
+ redisContext *c;
+
+ test("Set error when an invalid timeout usec value is given to redisConnectWithTimeout: ");
+
+ config.tcp.timeout.tv_sec = 0;
+ config.tcp.timeout.tv_usec = 10000001;
+
+ c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout);
+
+ test_cond(c->err == REDIS_ERR_IO);
+
+ test("Set error when an invalid timeout sec value is given to redisConnectWithTimeout: ");
+
+ config.tcp.timeout.tv_sec = (((LONG_MAX) - 999) / 1000) + 1;
+ config.tcp.timeout.tv_usec = 0;
+
+ c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout);
+
+ test_cond(c->err == REDIS_ERR_IO);
+
+ redisFree(c);
+}
+
static void test_throughput(struct config config) {
redisContext *c = connect(config);
redisReply **replies;
@@ -643,6 +669,7 @@ int main(int argc, char **argv) {
cfg.type = CONN_TCP;
test_blocking_connection(cfg);
test_blocking_io_errors(cfg);
+ test_invalid_timeout_errors(cfg);
if (throughput) test_throughput(cfg);
printf("\nTesting against Unix socket connection (%s):\n", cfg.unix.path);