diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | fmacros.h | 4 | ||||
-rw-r--r-- | hiredis.c | 7 | ||||
-rw-r--r-- | hiredis.h | 3 | ||||
-rw-r--r-- | net.c | 40 | ||||
-rw-r--r-- | net.h | 1 | ||||
-rw-r--r-- | test.c | 27 |
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. @@ -13,4 +13,8 @@ #define _XOPEN_SOURCE #endif +#if __APPLE__ && __MACH__ +#define _OSX +#endif + #endif @@ -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. * @@ -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); @@ -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; } @@ -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 @@ -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); |