summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEddy Jansson <eddy@scmcoord.com>2014-02-24 11:41:00 +0100
committerMatt Stancliff <matt@genges.com>2014-04-09 17:02:42 -0400
commitae30d58ff91061e0b0f889f60a9ab2062fa4e9d0 (patch)
treeb51aac4c7f41b2ff02c99a731eabe6bc2c3b6dca
parent37d25a392c9b9468e064a67c504939c9c4ea0031 (diff)
Add redisConnectFd() and redisFreeKeepFd()
These allows for easier integration of hiredis with external code that wants to manage its fds, say for instance in a pool. Closes #223
-rw-r--r--hiredis.c19
-rw-r--r--hiredis.h2
-rw-r--r--test.c31
3 files changed, 47 insertions, 5 deletions
diff --git a/hiredis.c b/hiredis.c
index beed8e9..dcb13a5 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -1010,6 +1010,13 @@ void redisFree(redisContext *c) {
free(c);
}
+int redisFreeKeepFd(redisContext *c) {
+ int fd = c->fd;
+ c->fd = -1;
+ redisFree(c);
+ return fd;
+}
+
/* Connect to a Redis instance. On error the field error in the returned
* context will be set to the return value of the error function.
* When no set of reply functions is given, the default set will be used. */
@@ -1093,6 +1100,18 @@ redisContext *redisConnectUnixNonBlock(const char *path) {
return c;
}
+redisContext *redisConnectFd(int fd) {
+ redisContext *c;
+
+ c = redisContextInit();
+ if (c == NULL)
+ return NULL;
+
+ c->fd = fd;
+ c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
+ return c;
+}
+
/* Set read/write timeout on a blocking socket. */
int redisSetTimeout(redisContext *c, const struct timeval tv) {
if (c->flags & REDIS_BLOCK)
diff --git a/hiredis.h b/hiredis.h
index 6d24213..37d5779 100644
--- a/hiredis.h
+++ b/hiredis.h
@@ -179,9 +179,11 @@ redisContext *redisConnectBindNonBlock(const char *ip, int port, char *source);
redisContext *redisConnectUnix(const char *path);
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
redisContext *redisConnectUnixNonBlock(const char *path);
+redisContext *redisConnectFd(int fd);
int redisSetTimeout(redisContext *c, const struct timeval tv);
int redisEnableKeepAlive(redisContext *c);
void redisFree(redisContext *c);
+int redisFreeKeepFd(redisContext *c);
int redisBufferRead(redisContext *c);
int redisBufferWrite(redisContext *c, int *done);
diff --git a/test.c b/test.c
index b3b806f..75548b1 100644
--- a/test.c
+++ b/test.c
@@ -14,7 +14,8 @@
enum connection_type {
CONN_TCP,
- CONN_UNIX
+ CONN_UNIX,
+ CONN_FD
};
struct config {
@@ -64,7 +65,7 @@ static redisContext *select_database(redisContext *c) {
return c;
}
-static void disconnect(redisContext *c) {
+static int disconnect(redisContext *c, int keep_fd) {
redisReply *reply;
/* Make sure we're on DB 9. */
@@ -75,8 +76,11 @@ static void disconnect(redisContext *c) {
assert(reply != NULL);
freeReplyObject(reply);
- /* Free the context as well. */
+ /* Free the context as well, but keep the fd if requested. */
+ if (keep_fd)
+ return redisFreeKeepFd(c);
redisFree(c);
+ return -1;
}
static redisContext *connect(struct config config) {
@@ -86,6 +90,14 @@ static redisContext *connect(struct config config) {
c = redisConnect(config.tcp.host, config.tcp.port);
} else if (config.type == CONN_UNIX) {
c = redisConnectUnix(config.unix.path);
+ } else if (config.type == CONN_FD) {
+ /* Create a dummy connection just to get an fd to inherit */
+ redisContext *dummy_ctx = redisConnectUnix(config.unix.path);
+ if (dummy_ctx) {
+ int fd = disconnect(dummy_ctx, 1);
+ printf("Connecting to inherited fd %d\n", fd);
+ c = redisConnectFd(fd);
+ }
} else {
assert(NULL);
}
@@ -383,7 +395,7 @@ static void test_blocking_connection(struct config config) {
strcasecmp(reply->element[1]->str,"pong") == 0);
freeReplyObject(reply);
- disconnect(c);
+ disconnect(c, 0);
}
static void test_blocking_io_errors(struct config config) {
@@ -523,7 +535,7 @@ static void test_throughput(struct config config) {
free(replies);
printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
- disconnect(c);
+ disconnect(c, 0);
}
// static long __test_callback_flags = 0;
@@ -636,6 +648,7 @@ int main(int argc, char **argv) {
}
};
int throughput = 1;
+ int test_inherit_fd = 1;
/* Ignore broken pipe signal (for I/O error tests). */
signal(SIGPIPE, SIG_IGN);
@@ -654,6 +667,8 @@ int main(int argc, char **argv) {
cfg.unix.path = argv[0];
} else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) {
throughput = 0;
+ } else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) {
+ test_inherit_fd = 0;
} else {
fprintf(stderr, "Invalid argument: %s\n", argv[0]);
exit(1);
@@ -678,6 +693,12 @@ int main(int argc, char **argv) {
test_blocking_io_errors(cfg);
if (throughput) test_throughput(cfg);
+ if (test_inherit_fd) {
+ printf("\nTesting against inherited fd (%s):\n", cfg.unix.path);
+ cfg.type = CONN_FD;
+ test_blocking_connection(cfg);
+ }
+
if (fails) {
printf("*** %d TESTS FAILED ***\n", fails);
return 1;