diff options
author | Pieter Noordhuis <pcnoordhuis@gmail.com> | 2011-01-07 13:04:42 +0100 |
---|---|---|
committer | Pieter Noordhuis <pcnoordhuis@gmail.com> | 2011-01-07 13:04:42 +0100 |
commit | 43ab0f8018610efd8ca8ec146b4857f0b3298fb1 (patch) | |
tree | 9fb576f43e28e8258da4a5771cb131c66fabe839 | |
parent | ec922cd0075eee0628ee28857541900a496ea9e1 (diff) |
Return error on socket timeout for a blocking context
-rw-r--r-- | hiredis.c | 11 | ||||
-rw-r--r-- | hiredis.h | 2 | ||||
-rw-r--r-- | net.c | 14 | ||||
-rw-r--r-- | net.h | 1 | ||||
-rw-r--r-- | test.c | 11 |
5 files changed, 36 insertions, 3 deletions
@@ -851,6 +851,13 @@ redisContext *redisConnectUnixNonBlock(const char *path) { return c; } +/* Set read/write timeout on a blocking socket. */ +int redisSetTimeout(redisContext *c, struct timeval tv) { + if (c->flags & REDIS_BLOCK) + return redisContextSetTimeout(c,tv); + return REDIS_ERR; +} + /* Set the replyObjectFunctions to use. Returns REDIS_ERR when the reader * was already initialized and the function set could not be re-set. * Return REDIS_OK when they could be set. */ @@ -878,7 +885,7 @@ int redisBufferRead(redisContext *c) { char buf[2048]; int nread = read(c->fd,buf,sizeof(buf)); if (nread == -1) { - if (errno == EAGAIN) { + if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) { /* Try again later */ } else { __redisSetError(c,REDIS_ERR_IO,NULL); @@ -909,7 +916,7 @@ int redisBufferWrite(redisContext *c, int *done) { if (sdslen(c->obuf) > 0) { nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); if (nwritten == -1) { - if (errno == EAGAIN) { + if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) { /* Try again later */ } else { __redisSetError(c,REDIS_ERR_IO,NULL); @@ -33,6 +33,7 @@ #define __HIREDIS_H #include <stdio.h> /* for size_t */ #include <stdarg.h> /* for va_list */ +#include <sys/time.h> /* for struct timeval */ #define HIREDIS_MAJOR 0 #define HIREDIS_MINOR 9 @@ -146,6 +147,7 @@ redisContext *redisConnect(const char *ip, int port); redisContext *redisConnectNonBlock(const char *ip, int port); redisContext *redisConnectUnix(const char *path); redisContext *redisConnectUnixNonBlock(const char *path); +int redisSetTimeout(redisContext *c, struct timeval tv); int redisSetReplyObjectFunctions(redisContext *c, redisReplyObjectFunctions *fn); void redisFree(redisContext *c); int redisBufferRead(redisContext *c); @@ -98,6 +98,20 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) { return REDIS_OK; } +int redisContextSetTimeout(redisContext *c, struct timeval tv) { + if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) { + __redisSetError(c,REDIS_ERR_IO, + sdscatprintf(sdsempty(), "setsockopt(SO_RCVTIMEO): %s", strerror(errno))); + return REDIS_ERR; + } + if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) { + __redisSetError(c,REDIS_ERR_IO, + sdscatprintf(sdsempty(), "setsockopt(SO_SNDTIMEO): %s", strerror(errno))); + return REDIS_ERR; + } + return REDIS_OK; +} + int redisContextConnectTcp(redisContext *c, const char *addr, int port) { int s; int blocking = (c->flags & REDIS_BLOCK); @@ -39,6 +39,7 @@ #define AF_LOCAL AF_UNIX #endif +int redisContextSetTimeout(redisContext *c, struct timeval tv); int redisContextConnectTcp(redisContext *c, const char *addr, int port); int redisContextConnectUnix(redisContext *c, const char *path); @@ -6,6 +6,7 @@ #include <assert.h> #include <unistd.h> #include <signal.h> +#include <errno.h> #include "hiredis.h" @@ -246,9 +247,17 @@ static void test_blocking_connection() { * conditions, the error will be set to EOF. */ assert(c->err == REDIS_ERR_EOF && strcmp(c->errstr,"Server closed the connection") == 0); + redisFree(c); - /* Clean up context and reconnect again */ + __connect(&c); + test("Returns I/O error on socket timeout: "); + struct timeval tv = { 0, 1000 }; + assert(redisSetTimeout(c,tv) == REDIS_OK); + test_cond(redisGetReply(c,(void**)&reply) == REDIS_ERR && + c->err == REDIS_ERR_IO && errno == EAGAIN); redisFree(c); + + /* Context should be connected */ __connect(&c); } |