summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Noordhuis <pcnoordhuis@gmail.com>2011-01-07 13:04:42 +0100
committerPieter Noordhuis <pcnoordhuis@gmail.com>2011-01-07 13:04:42 +0100
commit43ab0f8018610efd8ca8ec146b4857f0b3298fb1 (patch)
tree9fb576f43e28e8258da4a5771cb131c66fabe839
parentec922cd0075eee0628ee28857541900a496ea9e1 (diff)
Return error on socket timeout for a blocking context
-rw-r--r--hiredis.c11
-rw-r--r--hiredis.h2
-rw-r--r--net.c14
-rw-r--r--net.h1
-rw-r--r--test.c11
5 files changed, 36 insertions, 3 deletions
diff --git a/hiredis.c b/hiredis.c
index 970b45a..ac6dc67 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -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);
diff --git a/hiredis.h b/hiredis.h
index 8c26a8f..8fdca4a 100644
--- a/hiredis.h
+++ b/hiredis.h
@@ -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);
diff --git a/net.c b/net.c
index d4a92ab..75cbe54 100644
--- a/net.c
+++ b/net.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);
diff --git a/net.h b/net.h
index 00ae32e..9d15fd2 100644
--- a/net.h
+++ b/net.h
@@ -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);
diff --git a/test.c b/test.c
index ed355a7..9ab0354 100644
--- a/test.c
+++ b/test.c
@@ -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);
}