summaryrefslogtreecommitdiff
path: root/deps/hiredis
diff options
context:
space:
mode:
authorMatt Stancliff <matt@genges.com>2014-04-24 15:14:54 -0400
committerantirez <antirez@gmail.com>2014-06-23 11:44:34 +0200
commit28f32c99d0118eb60b236a0c8a96ea4bd9b7fa5b (patch)
tree393b4873a2dc0a28e9f7110605f4eae672d20b75 /deps/hiredis
parentef897a41e80eb03a18d131d6a3c4d1d868f38ea0 (diff)
downloadredis-28f32c99d0118eb60b236a0c8a96ea4bd9b7fa5b.tar.gz
hiredis: Update to latest version
This is hiredis f225c276be7fd0646019b51023e3f41566633dfe This update includes all changes that diverged inside of Redis since the last update. This version also allows optional source address binding for connections which we need for some Sentinel deployments.
Diffstat (limited to 'deps/hiredis')
-rw-r--r--deps/hiredis/.gitignore2
-rw-r--r--deps/hiredis/.travis.yml6
-rw-r--r--deps/hiredis/CHANGELOG.md8
-rw-r--r--deps/hiredis/Makefile66
-rw-r--r--deps/hiredis/README.md9
-rw-r--r--deps/hiredis/adapters/libuv.h121
-rw-r--r--deps/hiredis/async.c59
-rw-r--r--deps/hiredis/async.h1
-rw-r--r--deps/hiredis/examples/example-ae.c (renamed from deps/hiredis/example-ae.c)14
-rw-r--r--deps/hiredis/examples/example-libev.c (renamed from deps/hiredis/example-libev.c)7
-rw-r--r--deps/hiredis/examples/example-libevent.c (renamed from deps/hiredis/example-libevent.c)7
-rw-r--r--deps/hiredis/examples/example-libuv.c53
-rw-r--r--deps/hiredis/examples/example.c (renamed from deps/hiredis/example.c)22
-rw-r--r--deps/hiredis/fmacros.h4
-rw-r--r--deps/hiredis/hiredis.c99
-rw-r--r--deps/hiredis/hiredis.h20
-rw-r--r--deps/hiredis/net.c166
-rw-r--r--deps/hiredis/net.h12
-rw-r--r--deps/hiredis/sds.c113
-rw-r--r--deps/hiredis/sds.h13
-rw-r--r--deps/hiredis/test.c111
-rw-r--r--deps/hiredis/zmalloc.h13
22 files changed, 730 insertions, 196 deletions
diff --git a/deps/hiredis/.gitignore b/deps/hiredis/.gitignore
index 1a4d60d28..0c166a02e 100644
--- a/deps/hiredis/.gitignore
+++ b/deps/hiredis/.gitignore
@@ -1,5 +1,5 @@
/hiredis-test
-/hiredis-example*
+/examples/hiredis-example*
/*.o
/*.so
/*.dylib
diff --git a/deps/hiredis/.travis.yml b/deps/hiredis/.travis.yml
new file mode 100644
index 000000000..030427ff4
--- /dev/null
+++ b/deps/hiredis/.travis.yml
@@ -0,0 +1,6 @@
+language: c
+compiler:
+ - gcc
+ - clang
+
+script: make && make check
diff --git a/deps/hiredis/CHANGELOG.md b/deps/hiredis/CHANGELOG.md
index d41db8a60..268b15cd5 100644
--- a/deps/hiredis/CHANGELOG.md
+++ b/deps/hiredis/CHANGELOG.md
@@ -1,3 +1,11 @@
+### 0.11.0
+
+* Increase the maximum multi-bulk reply depth to 7.
+
+* Increase the read buffer size from 2k to 16k.
+
+* Use poll(2) instead of select(2) to support large fds (>= 1024).
+
### 0.10.1
* Makefile overhaul. Important to check out if you override one or more
diff --git a/deps/hiredis/Makefile b/deps/hiredis/Makefile
index 16b8767b1..ddcc4e4f6 100644
--- a/deps/hiredis/Makefile
+++ b/deps/hiredis/Makefile
@@ -4,11 +4,24 @@
# This file is released under the BSD license, see the COPYING file
OBJ=net.o hiredis.o sds.o async.o
-BINS=hiredis-example hiredis-test
+EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev
+TESTS=hiredis-test
LIBNAME=libhiredis
HIREDIS_MAJOR=0
-HIREDIS_MINOR=10
+HIREDIS_MINOR=11
+
+# redis-server configuration used for testing
+REDIS_PORT=56379
+REDIS_SERVER=redis-server
+define REDIS_TEST_CONFIG
+ daemonize yes
+ pidfile /tmp/hiredis-test-redis.pid
+ port $(REDIS_PORT)
+ bind 127.0.0.1
+ unixsocket /tmp/hiredis-test-redis.sock
+endef
+export REDIS_TEST_CONFIG
# Fallback to gcc when $CC is not in $PATH.
CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
@@ -41,12 +54,11 @@ ifeq ($(uname_S),Darwin)
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
endif
-all: $(DYLIBNAME) $(BINS)
+all: $(DYLIBNAME)
# Deps (use make dep to generate this)
net.o: net.c fmacros.h net.h hiredis.h
async.o: async.c async.h hiredis.h sds.h dict.c dict.h
-example.o: example.c hiredis.h
hiredis.o: hiredis.c fmacros.h hiredis.h net.h sds.h
sds.o: sds.c sds.h
test.o: test.c hiredis.h
@@ -61,36 +73,44 @@ dynamic: $(DYLIBNAME)
static: $(STLIBNAME)
# Binaries:
-hiredis-example-libevent: example-libevent.c adapters/libevent.h $(STLIBNAME)
- $(CC) -o $@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -levent example-libevent.c $(STLIBNAME)
+hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME)
-hiredis-example-libev: example-libev.c adapters/libev.h $(STLIBNAME)
- $(CC) -o $@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -lev example-libev.c $(STLIBNAME)
+hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME)
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME)
ifndef AE_DIR
hiredis-example-ae:
@echo "Please specify AE_DIR (e.g. <redis repository>/src)"
@false
else
-hiredis-example-ae: example-ae.c adapters/ae.h $(STLIBNAME)
- $(CC) -o $@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I$(AE_DIR) $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o example-ae.c $(STLIBNAME)
+hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME)
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME)
endif
-hiredis-%: %.o $(STLIBNAME)
+ifndef LIBUV_DIR
+hiredis-example-libuv:
+ @echo "Please specify LIBUV_DIR (e.g. ../libuv/)"
+ @false
+else
+hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread $(STLIBNAME)
+endif
+
+hiredis-example: examples/example.c $(STLIBNAME)
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME)
+
+examples: $(EXAMPLES)
+
+hiredis-test: test.o $(STLIBNAME)
$(CC) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
test: hiredis-test
./hiredis-test
check: hiredis-test
- echo \
- "daemonize yes\n" \
- "pidfile /tmp/hiredis-test-redis.pid\n" \
- "port 56379\n" \
- "bind 127.0.0.1\n" \
- "unixsocket /tmp/hiredis-test-redis.sock" \
- | redis-server -
- ./hiredis-test -h 127.0.0.1 -p 56379 -s /tmp/hiredis-test-redis.sock || \
+ @echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) -
+ ./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \
( kill `cat /tmp/hiredis-test-redis.pid` && false )
kill `cat /tmp/hiredis-test-redis.pid`
@@ -98,17 +118,15 @@ check: hiredis-test
$(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $<
clean:
- rm -rf $(DYLIBNAME) $(STLIBNAME) $(BINS) hiredis-example* *.o *.gcda *.gcno *.gcov
+ rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
dep:
$(CC) -MM *.c
# Installation related variables and target
PREFIX?=/usr/local
-INCLUDE_PATH?=include/hiredis
-LIBRARY_PATH?=lib
-INSTALL_INCLUDE_PATH= $(PREFIX)/$(INCLUDE_PATH)
-INSTALL_LIBRARY_PATH= $(PREFIX)/$(LIBRARY_PATH)
+INSTALL_INCLUDE_PATH= $(PREFIX)/include/hiredis
+INSTALL_LIBRARY_PATH= $(PREFIX)/lib
ifeq ($(uname_S),SunOS)
INSTALL?= cp -r
diff --git a/deps/hiredis/README.md b/deps/hiredis/README.md
index 62fe1067b..dba4a8c8e 100644
--- a/deps/hiredis/README.md
+++ b/deps/hiredis/README.md
@@ -1,3 +1,5 @@
+[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis)
+
# HIREDIS
Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database.
@@ -44,7 +46,7 @@ After trying to connect to Redis using `redisConnect` you should
check the `err` field to see if establishing the connection was successful:
redisContext *c = redisConnect("127.0.0.1", 6379);
- if (c->err) {
+ if (c != NULL && c->err) {
printf("Error: %s\n", c->errstr);
// handle error
}
@@ -66,7 +68,7 @@ When you need to pass binary safe strings in a command, the `%b` specifier can b
used. Together with a pointer to the string, it requires a `size_t` length argument
of the string:
- reply = redisCommand(context, "SET foo %b", value, valuelen);
+ reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
Internally, Hiredis splits the command in different arguments and will
convert it to the protocol used to communicate with Redis.
@@ -337,6 +339,9 @@ and a reply object (as described above) via `void **reply`. The returned status
can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went
wrong (either a protocol error, or an out of memory error).
+The parser limits the level of nesting for multi bulk payloads to 7. If the
+multi bulk nesting level is higher than this, the parser returns an error.
+
### Customizing replies
The function `redisReaderGetReply` creates `redisReply` and makes the function
diff --git a/deps/hiredis/adapters/libuv.h b/deps/hiredis/adapters/libuv.h
new file mode 100644
index 000000000..a1967f4fd
--- /dev/null
+++ b/deps/hiredis/adapters/libuv.h
@@ -0,0 +1,121 @@
+#ifndef __HIREDIS_LIBUV_H__
+#define __HIREDIS_LIBUV_H__
+#include <uv.h>
+#include "../hiredis.h"
+#include "../async.h"
+#include <string.h>
+
+typedef struct redisLibuvEvents {
+ redisAsyncContext* context;
+ uv_poll_t handle;
+ int events;
+} redisLibuvEvents;
+
+int redisLibuvAttach(redisAsyncContext*, uv_loop_t*);
+
+static void redisLibuvPoll(uv_poll_t* handle, int status, int events) {
+ redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
+
+ if (status != 0) {
+ return;
+ }
+
+ if (events & UV_READABLE) {
+ redisAsyncHandleRead(p->context);
+ }
+ if (events & UV_WRITABLE) {
+ redisAsyncHandleWrite(p->context);
+ }
+}
+
+
+static void redisLibuvAddRead(void *privdata) {
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+
+ p->events |= UV_READABLE;
+
+ uv_poll_start(&p->handle, p->events, redisLibuvPoll);
+}
+
+
+static void redisLibuvDelRead(void *privdata) {
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+
+ p->events &= ~UV_READABLE;
+
+ if (p->events) {
+ uv_poll_start(&p->handle, p->events, redisLibuvPoll);
+ } else {
+ uv_poll_stop(&p->handle);
+ }
+}
+
+
+static void redisLibuvAddWrite(void *privdata) {
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+
+ p->events |= UV_WRITABLE;
+
+ uv_poll_start(&p->handle, p->events, redisLibuvPoll);
+}
+
+
+static void redisLibuvDelWrite(void *privdata) {
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+
+ p->events &= ~UV_WRITABLE;
+
+ if (p->events) {
+ uv_poll_start(&p->handle, p->events, redisLibuvPoll);
+ } else {
+ uv_poll_stop(&p->handle);
+ }
+}
+
+
+static void on_close(uv_handle_t* handle) {
+ redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
+
+ free(p);
+}
+
+
+static void redisLibuvCleanup(void *privdata) {
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+
+ uv_close((uv_handle_t*)&p->handle, on_close);
+}
+
+
+static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
+ redisContext *c = &(ac->c);
+
+ if (ac->ev.data != NULL) {
+ return REDIS_ERR;
+ }
+
+ ac->ev.addRead = redisLibuvAddRead;
+ ac->ev.delRead = redisLibuvDelRead;
+ ac->ev.addWrite = redisLibuvAddWrite;
+ ac->ev.delWrite = redisLibuvDelWrite;
+ ac->ev.cleanup = redisLibuvCleanup;
+
+ redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p));
+
+ if (!p) {
+ return REDIS_ERR;
+ }
+
+ memset(p, 0, sizeof(*p));
+
+ if (uv_poll_init(loop, &p->handle, c->fd) != 0) {
+ return REDIS_ERR;
+ }
+
+ ac->ev.data = p;
+ p->handle.data = p;
+ p->context = ac;
+
+ return REDIS_OK;
+}
+#endif
diff --git a/deps/hiredis/async.c b/deps/hiredis/async.c
index f65f8694c..f7f343bef 100644
--- a/deps/hiredis/async.c
+++ b/deps/hiredis/async.c
@@ -62,7 +62,8 @@ void __redisAppendCommand(redisContext *c, char *cmd, size_t len);
/* Functions managing dictionary of callbacks for pub/sub. */
static unsigned int callbackHash(const void *key) {
- return dictGenHashFunction((unsigned char*)key,sdslen((char*)key));
+ return dictGenHashFunction((const unsigned char *)key,
+ sdslen((const sds)key));
}
static void *callbackValDup(void *privdata, const void *src) {
@@ -76,8 +77,8 @@ static int callbackKeyCompare(void *privdata, const void *key1, const void *key2
int l1, l2;
((void) privdata);
- l1 = sdslen((sds)key1);
- l2 = sdslen((sds)key2);
+ l1 = sdslen((const sds)key1);
+ l2 = sdslen((const sds)key2);
if (l1 != l2) return 0;
return memcmp(key1,key2,l1) == 0;
}
@@ -102,7 +103,12 @@ static dictType callbackDict = {
};
static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
- redisAsyncContext *ac = realloc(c,sizeof(redisAsyncContext));
+ redisAsyncContext *ac;
+
+ ac = realloc(c,sizeof(redisAsyncContext));
+ if (ac == NULL)
+ return NULL;
+
c = &(ac->c);
/* The regular connect functions will always set the flag REDIS_CONNECTED.
@@ -142,15 +148,45 @@ static void __redisAsyncCopyError(redisAsyncContext *ac) {
}
redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
- redisContext *c = redisConnectNonBlock(ip,port);
+ redisContext *c;
+ redisAsyncContext *ac;
+
+ c = redisConnectNonBlock(ip,port);
+ if (c == NULL)
+ return NULL;
+
+ ac = redisAsyncInitialize(c);
+ if (ac == NULL) {
+ redisFree(c);
+ return NULL;
+ }
+
+ __redisAsyncCopyError(ac);
+ return ac;
+}
+
+redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,
+ const char *source_addr) {
+ redisContext *c = redisConnectBindNonBlock(ip,port,source_addr);
redisAsyncContext *ac = redisAsyncInitialize(c);
__redisAsyncCopyError(ac);
return ac;
}
redisAsyncContext *redisAsyncConnectUnix(const char *path) {
- redisContext *c = redisConnectUnixNonBlock(path);
- redisAsyncContext *ac = redisAsyncInitialize(c);
+ redisContext *c;
+ redisAsyncContext *ac;
+
+ c = redisConnectUnixNonBlock(path);
+ if (c == NULL)
+ return NULL;
+
+ ac = redisAsyncInitialize(c);
+ if (ac == NULL) {
+ redisFree(c);
+ return NULL;
+ }
+
__redisAsyncCopyError(ac);
return ac;
}
@@ -182,6 +218,9 @@ static int __redisPushCallback(redisCallbackList *list, redisCallback *source) {
/* Copy callback from stack to heap */
cb = malloc(sizeof(*cb));
+ if (cb == NULL)
+ return REDIS_ERR_OOM;
+
if (source != NULL) {
memcpy(cb,source,sizeof(*cb));
cb->next = NULL;
@@ -360,7 +399,7 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
void redisProcessCallbacks(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
- redisCallback cb;
+ redisCallback cb = {NULL, NULL, NULL};
void *reply = NULL;
int status;
@@ -372,7 +411,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
__redisAsyncDisconnect(ac);
return;
}
-
+
/* If monitor mode, repush callback */
if(c->flags & REDIS_MONITORING) {
__redisPushCallback(&ac->replies,&cb);
@@ -442,7 +481,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
- if (redisCheckSocketError(c,c->fd) == REDIS_ERR) {
+ if (redisCheckSocketError(c) == REDIS_ERR) {
/* Try again later when connect(2) is still in progress. */
if (errno == EINPROGRESS)
return REDIS_OK;
diff --git a/deps/hiredis/async.h b/deps/hiredis/async.h
index 268274e8e..8a2cf1ecd 100644
--- a/deps/hiredis/async.h
+++ b/deps/hiredis/async.h
@@ -102,6 +102,7 @@ typedef struct redisAsyncContext {
/* Functions that proxy to hiredis */
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
+redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
redisAsyncContext *redisAsyncConnectUnix(const char *path);
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
diff --git a/deps/hiredis/example-ae.c b/deps/hiredis/examples/example-ae.c
index 5ed34a3a6..8efa7306a 100644
--- a/deps/hiredis/example-ae.c
+++ b/deps/hiredis/examples/example-ae.c
@@ -2,9 +2,10 @@
#include <stdlib.h>
#include <string.h>
#include <signal.h>
-#include "hiredis.h"
-#include "async.h"
-#include "adapters/ae.h"
+
+#include <hiredis.h>
+#include <async.h>
+#include <adapters/ae.h>
/* Put event loop in the global scope, so it can be explicitly stopped */
static aeEventLoop *loop;
@@ -21,17 +22,22 @@ void getCallback(redisAsyncContext *c, void *r, void *privdata) {
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
+ aeStop(loop);
return;
}
+
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
+ aeStop(loop);
return;
}
+
printf("Disconnected...\n");
+ aeStop(loop);
}
int main (int argc, char **argv) {
@@ -44,7 +50,7 @@ int main (int argc, char **argv) {
return 1;
}
- loop = aeCreateEventLoop();
+ loop = aeCreateEventLoop(64);
redisAeAttach(loop, c);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
diff --git a/deps/hiredis/example-libev.c b/deps/hiredis/examples/example-libev.c
index 7894f1f48..cc8b166ec 100644
--- a/deps/hiredis/example-libev.c
+++ b/deps/hiredis/examples/example-libev.c
@@ -2,9 +2,10 @@
#include <stdlib.h>
#include <string.h>
#include <signal.h>
-#include "hiredis.h"
-#include "async.h"
-#include "adapters/libev.h"
+
+#include <hiredis.h>
+#include <async.h>
+#include <adapters/libev.h>
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
diff --git a/deps/hiredis/example-libevent.c b/deps/hiredis/examples/example-libevent.c
index 9da8e02bf..d333c22b7 100644
--- a/deps/hiredis/example-libevent.c
+++ b/deps/hiredis/examples/example-libevent.c
@@ -2,9 +2,10 @@
#include <stdlib.h>
#include <string.h>
#include <signal.h>
-#include "hiredis.h"
-#include "async.h"
-#include "adapters/libevent.h"
+
+#include <hiredis.h>
+#include <async.h>
+#include <adapters/libevent.h>
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
diff --git a/deps/hiredis/examples/example-libuv.c b/deps/hiredis/examples/example-libuv.c
new file mode 100644
index 000000000..a5462d410
--- /dev/null
+++ b/deps/hiredis/examples/example-libuv.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <hiredis.h>
+#include <async.h>
+#include <adapters/libuv.h>
+
+void getCallback(redisAsyncContext *c, void *r, void *privdata) {
+ redisReply *reply = r;
+ if (reply == NULL) return;
+ printf("argv[%s]: %s\n", (char*)privdata, reply->str);
+
+ /* Disconnect after receiving the reply to GET */
+ redisAsyncDisconnect(c);
+}
+
+void connectCallback(const redisAsyncContext *c, int status) {
+ if (status != REDIS_OK) {
+ printf("Error: %s\n", c->errstr);
+ return;
+ }
+ printf("Connected...\n");
+}
+
+void disconnectCallback(const redisAsyncContext *c, int status) {
+ if (status != REDIS_OK) {
+ printf("Error: %s\n", c->errstr);
+ return;
+ }
+ printf("Disconnected...\n");
+}
+
+int main (int argc, char **argv) {
+ signal(SIGPIPE, SIG_IGN);
+ uv_loop_t* loop = uv_default_loop();
+
+ redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
+ if (c->err) {
+ /* Let *c leak for now... */
+ printf("Error: %s\n", c->errstr);
+ return 1;
+ }
+
+ redisLibuvAttach(c,loop);
+ redisAsyncSetConnectCallback(c,connectCallback);
+ redisAsyncSetDisconnectCallback(c,disconnectCallback);
+ redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
+ redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
diff --git a/deps/hiredis/example.c b/deps/hiredis/examples/example.c
index 90ff9ed5e..25226a807 100644
--- a/deps/hiredis/example.c
+++ b/deps/hiredis/examples/example.c
@@ -2,17 +2,24 @@
#include <stdlib.h>
#include <string.h>
-#include "hiredis.h"
+#include <hiredis.h>
-int main(void) {
+int main(int argc, char **argv) {
unsigned int j;
redisContext *c;
redisReply *reply;
+ const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
+ int port = (argc > 2) ? atoi(argv[2]) : 6379;
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
- c = redisConnectWithTimeout((char*)"127.0.0.2", 6379, timeout);
- if (c->err) {
- printf("Connection error: %s\n", c->errstr);
+ c = redisConnectWithTimeout(hostname, port, timeout);
+ if (c == NULL || c->err) {
+ if (c) {
+ printf("Connection error: %s\n", c->errstr);
+ redisFree(c);
+ } else {
+ printf("Connection error: can't allocate redis context\n");
+ }
exit(1);
}
@@ -27,7 +34,7 @@ int main(void) {
freeReplyObject(reply);
/* Set a key using binary safe API */
- reply = redisCommand(c,"SET %b %b", "bar", 3, "hello", 5);
+ reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
printf("SET (binary API): %s\n", reply->str);
freeReplyObject(reply);
@@ -64,5 +71,8 @@ int main(void) {
}
freeReplyObject(reply);
+ /* Disconnects and frees the context */
+ redisFree(c);
+
return 0;
}
diff --git a/deps/hiredis/fmacros.h b/deps/hiredis/fmacros.h
index 96324eb49..9e5fec0ce 100644
--- a/deps/hiredis/fmacros.h
+++ b/deps/hiredis/fmacros.h
@@ -13,4 +13,8 @@
#define _XOPEN_SOURCE
#endif
+#if __APPLE__ && __MACH__
+#define _OSX
+#endif
+
#endif
diff --git a/deps/hiredis/hiredis.c b/deps/hiredis/hiredis.c
index 0b04935a1..2afee5666 100644
--- a/deps/hiredis/hiredis.c
+++ b/deps/hiredis/hiredis.c
@@ -917,7 +917,7 @@ err:
* %b represents a binary safe string
*
* When using %b you need to provide both the pointer to the string
- * and the length in bytes. Examples:
+ * and the length in bytes as a size_t. Examples:
*
* len = redisFormatCommand(target, "GET %s", mykey);
* len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
@@ -1010,58 +1010,122 @@ 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. */
redisContext *redisConnect(const char *ip, int port) {
- redisContext *c = redisContextInit();
+ redisContext *c;
+
+ c = redisContextInit();
+ if (c == NULL)
+ return NULL;
+
c->flags |= REDIS_BLOCK;
redisContextConnectTcp(c,ip,port,NULL);
return c;
}
-redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv) {
- redisContext *c = redisContextInit();
+redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
+ redisContext *c;
+
+ c = redisContextInit();
+ if (c == NULL)
+ return NULL;
+
c->flags |= REDIS_BLOCK;
redisContextConnectTcp(c,ip,port,&tv);
return c;
}
redisContext *redisConnectNonBlock(const char *ip, int port) {
- redisContext *c = redisContextInit();
+ redisContext *c;
+
+ c = redisContextInit();
+ if (c == NULL)
+ return NULL;
+
c->flags &= ~REDIS_BLOCK;
redisContextConnectTcp(c,ip,port,NULL);
return c;
}
-redisContext *redisConnectUnix(const char *path) {
+redisContext *redisConnectBindNonBlock(const char *ip, int port,
+ const char *source_addr) {
redisContext *c = redisContextInit();
+ c->flags &= ~REDIS_BLOCK;
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
+ return c;
+}
+
+redisContext *redisConnectUnix(const char *path) {
+ redisContext *c;
+
+ c = redisContextInit();
+ if (c == NULL)
+ return NULL;
+
c->flags |= REDIS_BLOCK;
redisContextConnectUnix(c,path,NULL);
return c;
}
-redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv) {
- redisContext *c = redisContextInit();
+redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
+ redisContext *c;
+
+ c = redisContextInit();
+ if (c == NULL)
+ return NULL;
+
c->flags |= REDIS_BLOCK;
redisContextConnectUnix(c,path,&tv);
return c;
}
redisContext *redisConnectUnixNonBlock(const char *path) {
- redisContext *c = redisContextInit();
+ redisContext *c;
+
+ c = redisContextInit();
+ if (c == NULL)
+ return NULL;
+
c->flags &= ~REDIS_BLOCK;
redisContextConnectUnix(c,path,NULL);
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, struct timeval tv) {
+int redisSetTimeout(redisContext *c, const struct timeval tv) {
if (c->flags & REDIS_BLOCK)
return redisContextSetTimeout(c,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.
*
@@ -1077,7 +1141,7 @@ int redisBufferRead(redisContext *c) {
nread = read(c->fd,buf,sizeof(buf));
if (nread == -1) {
- if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
} else {
__redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1114,7 +1178,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 && !(c->flags & REDIS_BLOCK)) {
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
} else {
__redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1180,7 +1244,7 @@ int redisGetReply(redisContext *c, void **reply) {
* is used, you need to call redisGetReply yourself to retrieve
* the reply (or replies in pub/sub).
*/
-int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
+int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
sds newbuf;
newbuf = sdscatlen(c->obuf,cmd,len);
@@ -1193,6 +1257,15 @@ int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
return REDIS_OK;
}
+int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
+
+ if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
+ return REDIS_ERR;
+ }
+
+ return REDIS_OK;
+}
+
int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
char *cmd;
int len;
diff --git a/deps/hiredis/hiredis.h b/deps/hiredis/hiredis.h
index b922831e3..7700f4b89 100644
--- a/deps/hiredis/hiredis.h
+++ b/deps/hiredis/hiredis.h
@@ -36,8 +36,8 @@
#include <sys/time.h> /* for struct timeval */
#define HIREDIS_MAJOR 0
-#define HIREDIS_MINOR 10
-#define HIREDIS_PATCH 1
+#define HIREDIS_MINOR 11
+#define HIREDIS_PATCH 0
#define REDIS_ERR -1
#define REDIS_OK 0
@@ -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
@@ -171,13 +173,17 @@ typedef struct redisContext {
} redisContext;
redisContext *redisConnect(const char *ip, int port);
-redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv);
+redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
redisContext *redisConnectNonBlock(const char *ip, int port);
+redisContext *redisConnectBindNonBlock(const char *ip, int port, const char *source_addr);
redisContext *redisConnectUnix(const char *path);
-redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv);
+redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
redisContext *redisConnectUnixNonBlock(const char *path);
-int redisSetTimeout(redisContext *c, struct timeval tv);
+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);
@@ -188,6 +194,10 @@ int redisBufferWrite(redisContext *c, int *done);
int redisGetReply(redisContext *c, void **reply);
int redisGetReplyFromReader(redisContext *c, void **reply);
+/* Write a formatted command to the output buffer. Use these functions in blocking mode
+ * to get a pipeline of commands. */
+int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len);
+
/* Write a command to the output buffer. Use these functions in blocking mode
* to get a pipeline of commands. */
int redisvAppendCommand(redisContext *c, const char *format, va_list ap);
diff --git a/deps/hiredis/net.c b/deps/hiredis/net.c
index b10eee2e5..9fe80bba7 100644
--- a/deps/hiredis/net.c
+++ b/deps/hiredis/net.c
@@ -54,8 +54,15 @@
/* Defined in hiredis.c */
void __redisSetError(redisContext *c, int type, const char *str);
+static void redisContextCloseFd(redisContext *c) {
+ if (c && c->fd >= 0) {
+ close(c->fd);
+ c->fd = -1;
+ }
+}
+
static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
- char buf[128];
+ char buf[128] = { 0 };
size_t len = 0;
if (prefix != NULL)
@@ -64,11 +71,11 @@ static void __redisSetErrorFromErrno(redisContext *c, int type, const char *pref
__redisSetError(c,type,buf);
}
-static int redisSetReuseAddr(redisContext *c, int fd) {
+static int redisSetReuseAddr(redisContext *c) {
int on = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
+ if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
- close(fd);
+ redisContextCloseFd(c);
return REDIS_ERR;
}
return REDIS_OK;
@@ -80,23 +87,24 @@ static int redisCreateSocket(redisContext *c, int type) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
return REDIS_ERR;
}
+ c->fd = s;
if (type == AF_INET) {
- if (redisSetReuseAddr(c,s) == REDIS_ERR) {
+ if (redisSetReuseAddr(c) == REDIS_ERR) {
return REDIS_ERR;
}
}
- return s;
+ return REDIS_OK;
}
-static int redisSetBlocking(redisContext *c, int fd, int blocking) {
+static int redisSetBlocking(redisContext *c, int blocking) {
int flags;
/* Set the socket nonblocking.
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. */
- if ((flags = fcntl(fd, F_GETFL)) == -1) {
+ if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
- close(fd);
+ redisContextCloseFd(c);
return REDIS_ERR;
}
@@ -105,19 +113,61 @@ static int redisSetBlocking(redisContext *c, int fd, int blocking) {
else
flags |= O_NONBLOCK;
- if (fcntl(fd, F_SETFL, flags) == -1) {
+ if (fcntl(c->fd, F_SETFL, flags) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
- close(fd);
+ redisContextCloseFd(c);
+ return REDIS_ERR;
+ }
+ 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;
+ }
+
+ val = interval;
+
+#ifdef _OSX
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
+ __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
+ return REDIS_ERR;
+ }
+#else
+#ifndef __sun
+ 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
+#endif
+
return REDIS_OK;
}
-static int redisSetTcpNoDelay(redisContext *c, int fd) {
+static int redisSetTcpNoDelay(redisContext *c) {
int yes = 1;
- if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
- close(fd);
+ redisContextCloseFd(c);
return REDIS_ERR;
}
return REDIS_OK;
@@ -125,18 +175,19 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
-static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *timeout) {
+static int redisContextWaitReady(redisContext *c, const struct timeval *timeout) {
struct pollfd wfd[1];
long msec;
msec = -1;
- wfd[0].fd = fd;
+ wfd[0].fd = c->fd;
wfd[0].events = POLLOUT;
/* Only use timeout when not NULL. */
if (timeout != NULL) {
if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
- close(fd);
+ __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
+ redisContextCloseFd(c);
return REDIS_ERR;
}
@@ -152,47 +203,45 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
if ((res = poll(wfd, 1, msec)) == -1) {
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
- close(fd);
+ redisContextCloseFd(c);
return REDIS_ERR;
} else if (res == 0) {
errno = ETIMEDOUT;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
- close(fd);
+ redisContextCloseFd(c);
return REDIS_ERR;
}
- if (redisCheckSocketError(c, fd) != REDIS_OK)
+ if (redisCheckSocketError(c) != REDIS_OK)
return REDIS_ERR;
return REDIS_OK;
}
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
- close(fd);
+ redisContextCloseFd(c);
return REDIS_ERR;
}
-int redisCheckSocketError(redisContext *c, int fd) {
+int redisCheckSocketError(redisContext *c) {
int err = 0;
socklen_t errlen = sizeof(err);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
+ if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)");
- close(fd);
return REDIS_ERR;
}
if (err) {
errno = err;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
- close(fd);
return REDIS_ERR;
}
return REDIS_OK;
}
-int redisContextSetTimeout(redisContext *c, struct timeval tv) {
+int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
return REDIS_ERR;
@@ -204,10 +253,12 @@ int redisContextSetTimeout(redisContext *c, struct timeval tv) {
return REDIS_OK;
}
-int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout) {
+static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
+ const struct timeval *timeout,
+ const char *source_addr) {
int s, rv;
char _port[6]; /* strlen("65535"); */
- struct addrinfo hints, *servinfo, *p;
+ struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
int blocking = (c->flags & REDIS_BLOCK);
snprintf(_port, 6, "%d", port);
@@ -231,25 +282,47 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
continue;
- if (redisSetBlocking(c,s,0) != REDIS_OK)
+ c->fd = s;
+ if (redisSetBlocking(c,0) != REDIS_OK)
goto error;
+ if (source_addr) {
+ int bound = 0;
+ /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
+ if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) {
+ char buf[128];
+ snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv));
+ __redisSetError(c,REDIS_ERR_OTHER,buf);
+ goto error;
+ }
+ for (b = bservinfo; b != NULL; b = b->ai_next) {
+ if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
+ bound = 1;
+ break;
+ }
+ }
+ if (!bound) {
+ char buf[128];
+ snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno));
+ __redisSetError(c,REDIS_ERR_OTHER,buf);
+ goto error;
+ }
+ }
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
if (errno == EHOSTUNREACH) {
- close(s);
+ redisContextCloseFd(c);
continue;
} else if (errno == EINPROGRESS && !blocking) {
/* This is ok. */
} else {
- if (redisContextWaitReady(c,s,timeout) != REDIS_OK)
+ if (redisContextWaitReady(c,timeout) != REDIS_OK)
goto error;
}
}
- if (blocking && redisSetBlocking(c,s,1) != REDIS_OK)
+ if (blocking && redisSetBlocking(c,1) != REDIS_OK)
goto error;
- if (redisSetTcpNoDelay(c,s) != REDIS_OK)
+ if (redisSetTcpNoDelay(c) != REDIS_OK)
goto error;
- c->fd = s;
c->flags |= REDIS_CONNECTED;
rv = REDIS_OK;
goto end;
@@ -268,32 +341,41 @@ end:
return rv; // Need to return REDIS_OK if alright
}
-int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *timeout) {
- int s;
+int redisContextConnectTcp(redisContext *c, const char *addr, int port,
+ const struct timeval *timeout) {
+ return _redisContextConnectTcp(c, addr, port, timeout, NULL);
+}
+
+int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
+ const struct timeval *timeout,
+ const char *source_addr) {
+ return _redisContextConnectTcp(c, addr, port, timeout, source_addr);
+}
+
+int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
int blocking = (c->flags & REDIS_BLOCK);
struct sockaddr_un sa;
- if ((s = redisCreateSocket(c,AF_LOCAL)) < 0)
+ if (redisCreateSocket(c,AF_LOCAL) < 0)
return REDIS_ERR;
- if (redisSetBlocking(c,s,0) != REDIS_OK)
+ if (redisSetBlocking(c,0) != REDIS_OK)
return REDIS_ERR;
sa.sun_family = AF_LOCAL;
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
- if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
+ if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
if (errno == EINPROGRESS && !blocking) {
/* This is ok. */
} else {
- if (redisContextWaitReady(c,s,timeout) != REDIS_OK)
+ if (redisContextWaitReady(c,timeout) != REDIS_OK)
return REDIS_ERR;
}
}
/* Reset socket to be blocking after connect(2). */
- if (blocking && redisSetBlocking(c,s,1) != REDIS_OK)
+ if (blocking && redisSetBlocking(c,1) != REDIS_OK)
return REDIS_ERR;
- c->fd = s;
c->flags |= REDIS_CONNECTED;
return REDIS_OK;
}
diff --git a/deps/hiredis/net.h b/deps/hiredis/net.h
index eb8a0a1cf..5e742f577 100644
--- a/deps/hiredis/net.h
+++ b/deps/hiredis/net.h
@@ -39,9 +39,13 @@
#define AF_LOCAL AF_UNIX
#endif
-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 redisCheckSocketError(redisContext *c);
+int redisContextSetTimeout(redisContext *c, const struct timeval tv);
+int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
+int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
+ const struct timeval *timeout,
+ const char *source_addr);
+int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
+int redisKeepAlive(redisContext *c, int interval);
#endif
diff --git a/deps/hiredis/sds.c b/deps/hiredis/sds.c
index d66c1d730..5306f1ffb 100644
--- a/deps/hiredis/sds.c
+++ b/deps/hiredis/sds.c
@@ -1,6 +1,6 @@
-/* SDSLib, A C dynamic strings library
+/* SDS (Simple Dynamic Strings), A C dynamic strings library.
*
- * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2006-2014, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@
#include <string.h>
#include <ctype.h>
#include <assert.h>
+
#include "sds.h"
-#include "zmalloc.h"
/* Create a new sds string with the content specified by the 'init' pointer
* and 'initlen'.
@@ -52,9 +52,9 @@ sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
if (init) {
- sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
+ sh = malloc(sizeof *sh+initlen+1);
} else {
- sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
+ sh = calloc(sizeof *sh+initlen+1,1);
}
if (sh == NULL) return NULL;
sh->len = initlen;
@@ -85,7 +85,7 @@ sds sdsdup(const sds s) {
/* Free an sds string. No operation is performed if 's' is NULL. */
void sdsfree(sds s) {
if (s == NULL) return;
- zfree(s-sizeof(struct sdshdr));
+ free(s-sizeof(struct sdshdr));
}
/* Set the sds string length to the length as obtained with strlen(), so
@@ -103,7 +103,7 @@ void sdsfree(sds s) {
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
void sdsupdatelen(sds s) {
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*) (s-sizeof *sh);;
int reallen = strlen(s);
sh->free += (sh->len-reallen);
sh->len = reallen;
@@ -114,7 +114,7 @@ void sdsupdatelen(sds s) {
* so that next append operations will not require allocations up to the
* number of bytes previously available. */
void sdsclear(sds s) {
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*) (s-sizeof *sh);;
sh->free += sh->len;
sh->len = 0;
sh->buf[0] = '\0';
@@ -133,13 +133,13 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
if (free >= addlen) return s;
len = sdslen(s);
- sh = (void*) (s-(sizeof(struct sdshdr)));
+ sh = (void*) (s-sizeof *sh);;
newlen = (len+addlen);
if (newlen < SDS_MAX_PREALLOC)
newlen *= 2;
else
newlen += SDS_MAX_PREALLOC;
- newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
+ newsh = realloc(sh, sizeof *newsh+newlen+1);
if (newsh == NULL) return NULL;
newsh->free = newlen - len;
@@ -155,8 +155,8 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
sds sdsRemoveFreeSpace(sds s) {
struct sdshdr *sh;
- sh = (void*) (s-(sizeof(struct sdshdr)));
- sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);
+ sh = (void*) (s-sizeof *sh);;
+ sh = realloc(sh, sizeof *sh+sh->len+1);
sh->free = 0;
return sh->buf;
}
@@ -169,7 +169,7 @@ sds sdsRemoveFreeSpace(sds s) {
* 4) The implicit null term.
*/
size_t sdsAllocSize(sds s) {
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*) (s-sizeof *sh);;
return sizeof(*sh)+sh->len+sh->free+1;
}
@@ -198,7 +198,7 @@ size_t sdsAllocSize(sds s) {
* sdsIncrLen(s, nread);
*/
void sdsIncrLen(sds s, int incr) {
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*) (s-sizeof *sh);;
assert(sh->free >= incr);
sh->len += incr;
@@ -213,7 +213,7 @@ void sdsIncrLen(sds s, int incr) {
* if the specified length is smaller than the current length, no operation
* is performed. */
sds sdsgrowzero(sds s, size_t len) {
- struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
size_t totlen, curlen = sh->len;
if (len <= curlen) return s;
@@ -221,7 +221,7 @@ sds sdsgrowzero(sds s, size_t len) {
if (s == NULL) return NULL;
/* Make sure added region doesn't contain garbage */
- sh = (void*)(s-(sizeof(struct sdshdr)));
+ sh = (void*)(s-sizeof *sh);
memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
totlen = sh->len+sh->free;
sh->len = len;
@@ -240,7 +240,7 @@ sds sdscatlen(sds s, const void *t, size_t len) {
s = sdsMakeRoomFor(s,len);
if (s == NULL) return NULL;
- sh = (void*) (s-(sizeof(struct sdshdr)));
+ sh = (void*) (s-sizeof *sh);;
memcpy(s+curlen, t, len);
sh->len = curlen+len;
sh->free = sh->free-len;
@@ -267,13 +267,13 @@ sds sdscatsds(sds s, const sds t) {
/* Destructively modify the sds string 's' to hold the specified binary
* safe string pointed by 't' of length 'len' bytes. */
sds sdscpylen(sds s, const char *t, size_t len) {
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*) (s-sizeof *sh);;
size_t totlen = sh->free+sh->len;
if (totlen < len) {
s = sdsMakeRoomFor(s,len-sh->len);
if (s == NULL) return NULL;
- sh = (void*) (s-(sizeof(struct sdshdr)));
+ sh = (void*) (s-sizeof *sh);;
totlen = sh->free+sh->len;
}
memcpy(s, t, len);
@@ -296,20 +296,20 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
size_t buflen = 16;
while(1) {
- buf = zmalloc(buflen);
+ buf = malloc(buflen);
if (buf == NULL) return NULL;
buf[buflen-2] = '\0';
va_copy(cpy,ap);
vsnprintf(buf, buflen, fmt, cpy);
if (buf[buflen-2] != '\0') {
- zfree(buf);
+ free(buf);
buflen *= 2;
continue;
}
break;
}
t = sdscat(s, buf);
- zfree(buf);
+ free(buf);
return t;
}
@@ -352,8 +352,8 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
*
* Output will be just "Hello World".
*/
-sds sdstrim(sds s, const char *cset) {
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
+void sdstrim(sds s, const char *cset) {
+ struct sdshdr *sh = (void*) (s-sizeof *sh);;
char *start, *end, *sp, *ep;
size_t len;
@@ -366,7 +366,6 @@ sds sdstrim(sds s, const char *cset) {
sh->buf[len] = '\0';
sh->free = sh->free+(sh->len-len);
sh->len = len;
- return s;
}
/* Turn the string into a smaller (or equal) string containing only the
@@ -383,10 +382,10 @@ sds sdstrim(sds s, const char *cset) {
* Example:
*
* s = sdsnew("Hello World");
- * sdstrim(s,1,-1); => "ello Worl"
+ * sdsrange(s,1,-1); => "ello World"
*/
void sdsrange(sds s, int start, int end) {
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*) (s-sizeof *sh);;
size_t newlen, len = sdslen(s);
if (len == 0) return;
@@ -474,7 +473,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count
if (seplen < 1 || len < 0) return NULL;
- tokens = zmalloc(sizeof(sds)*slots);
+ tokens = malloc(sizeof(sds)*slots);
if (tokens == NULL) return NULL;
if (len == 0) {
@@ -487,7 +486,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count
sds *newtokens;
slots *= 2;
- newtokens = zrealloc(tokens,sizeof(sds)*slots);
+ newtokens = realloc(tokens,sizeof(sds)*slots);
if (newtokens == NULL) goto cleanup;
tokens = newtokens;
}
@@ -511,7 +510,7 @@ cleanup:
{
int i;
for (i = 0; i < elements; i++) sdsfree(tokens[i]);
- zfree(tokens);
+ free(tokens);
*count = 0;
return NULL;
}
@@ -522,7 +521,7 @@ void sdsfreesplitres(sds *tokens, int count) {
if (!tokens) return;
while(count--)
sdsfree(tokens[count]);
- zfree(tokens);
+ free(tokens);
}
/* Create an sds string from a long long value. It is much faster than:
@@ -582,7 +581,7 @@ int is_hex_digit(char c) {
(c >= 'A' && c <= 'F');
}
-/* Helper function for sdssplitargs() that converts an hex digit into an
+/* Helper function for sdssplitargs() that converts a hex digit into an
* integer from 0 to 15 */
int hex_digit_to_int(char c) {
switch(c) {
@@ -715,13 +714,13 @@ sds *sdssplitargs(const char *line, int *argc) {
if (*p) p++;
}
/* add the token to the vector */
- vector = zrealloc(vector,((*argc)+1)*sizeof(char*));
+ vector = realloc(vector,((*argc)+1)*sizeof(char*));
vector[*argc] = current;
(*argc)++;
current = NULL;
} else {
/* Even on empty input string return something not NULL. */
- if (vector == NULL) vector = zmalloc(sizeof(void*));
+ if (vector == NULL) vector = malloc(sizeof(void*));
return vector;
}
}
@@ -729,7 +728,7 @@ sds *sdssplitargs(const char *line, int *argc) {
err:
while((*argc)--)
sdsfree(vector[*argc]);
- zfree(vector);
+ free(vector);
if (current) sdsfree(current);
*argc = 0;
return NULL;
@@ -760,13 +759,25 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
/* Join an array of C strings using the specified separator (also a C string).
* Returns the result as an sds string. */
-sds sdsjoin(char **argv, int argc, char *sep) {
+sds sdsjoin(char **argv, int argc, char *sep, size_t seplen) {
sds join = sdsempty();
int j;
for (j = 0; j < argc; j++) {
join = sdscat(join, argv[j]);
- if (j != argc-1) join = sdscat(join,sep);
+ if (j != argc-1) join = sdscatlen(join,sep,seplen);
+ }
+ return join;
+}
+
+/* Like sdsjoin, but joins an array of SDS strings. */
+sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
+ sds join = sdsempty();
+ int j;
+
+ for (j = 0; j < argc; j++) {
+ join = sdscatsds(join, argv[j]);
+ if (j != argc-1) join = sdscatlen(join,sep,seplen);
}
return join;
}
@@ -807,36 +818,43 @@ int main(void) {
sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)
sdsfree(x);
- x = sdstrim(sdsnew("xxciaoyyy"),"xy");
+ x = sdsnew("xxciaoyyy");
+ sdstrim(x,"xy");
test_cond("sdstrim() correctly trims characters",
sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
- y = sdsrange(sdsdup(x),1,1);
+ y = sdsdup(x);
+ sdsrange(y,1,1);
test_cond("sdsrange(...,1,1)",
sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
sdsfree(y);
- y = sdsrange(sdsdup(x),1,-1);
+ y = sdsdup(x);
+ sdsrange(y,1,-1);
test_cond("sdsrange(...,1,-1)",
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
sdsfree(y);
- y = sdsrange(sdsdup(x),-2,-1);
+ y = sdsdup(x);
+ sdsrange(y,-2,-1);
test_cond("sdsrange(...,-2,-1)",
sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
sdsfree(y);
- y = sdsrange(sdsdup(x),2,1);
+ y = sdsdup(x);
+ sdsrange(y,2,1);
test_cond("sdsrange(...,2,1)",
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
sdsfree(y);
- y = sdsrange(sdsdup(x),1,100);
+ y = sdsdup(x);
+ sdsrange(y,1,100);
test_cond("sdsrange(...,1,100)",
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
sdsfree(y);
- y = sdsrange(sdsdup(x),100,100);
+ y = sdsdup(x);
+ sdsrange(y,100,100);
test_cond("sdsrange(...,100,100)",
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
@@ -858,6 +876,13 @@ int main(void) {
y = sdsnew("bar");
test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnewlen("\a\n\0foo\r",7);
+ y = sdscatrepr(sdsempty(),x,sdslen(x));
+ test_cond("sdscatrepr(...data...)",
+ memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
+
{
int oldfree;
diff --git a/deps/hiredis/sds.h b/deps/hiredis/sds.h
index 615c751cd..ab6fc9c05 100644
--- a/deps/hiredis/sds.h
+++ b/deps/hiredis/sds.h
@@ -1,6 +1,6 @@
-/* SDSLib, A C dynamic strings library
+/* SDS (Simple Dynamic Strings), A C dynamic strings library.
*
- * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2006-2014, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,12 +45,12 @@ struct sdshdr {
};
static inline size_t sdslen(const sds s) {
- struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*)(s-sizeof *sh);
return sh->len;
}
static inline size_t sdsavail(const sds s) {
- struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
+ struct sdshdr *sh = (void*)(s-sizeof *sh);
return sh->free;
}
@@ -76,7 +76,7 @@ sds sdscatprintf(sds s, const char *fmt, ...)
sds sdscatprintf(sds s, const char *fmt, ...);
#endif
-sds sdstrim(sds s, const char *cset);
+void sdstrim(sds s, const char *cset);
void sdsrange(sds s, int start, int end);
void sdsupdatelen(sds s);
void sdsclear(sds s);
@@ -89,7 +89,8 @@ sds sdsfromlonglong(long long value);
sds sdscatrepr(sds s, const char *p, size_t len);
sds *sdssplitargs(const char *line, int *argc);
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
-sds sdsjoin(char **argv, int argc, char *sep);
+sds sdsjoin(char **argv, int argc, char *sep, size_t seplen);
+sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
/* Low level functions exposed to the user API */
sds sdsMakeRoomFor(sds s, size_t addlen);
diff --git a/deps/hiredis/test.c b/deps/hiredis/test.c
index 5945b6552..713cc06c5 100644
--- a/deps/hiredis/test.c
+++ b/deps/hiredis/test.c
@@ -8,12 +8,14 @@
#include <unistd.h>
#include <signal.h>
#include <errno.h>
+#include <limits.h>
#include "hiredis.h"
enum connection_type {
CONN_TCP,
- CONN_UNIX
+ CONN_UNIX,
+ CONN_FD
};
struct config {
@@ -22,6 +24,7 @@ struct config {
struct {
const char *host;
int port;
+ struct timeval timeout;
} tcp;
struct {
@@ -62,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. */
@@ -73,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) {
@@ -84,11 +90,22 @@ 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);
}
- if (c->err) {
+ if (c == NULL) {
+ printf("Connection error: can't allocate redis context\n");
+ exit(1);
+ } else if (c->err) {
printf("Connection error: %s\n", c->errstr);
exit(1);
}
@@ -125,13 +142,13 @@ static void test_format_commands(void) {
free(cmd);
test("Format command with %%b string interpolation: ");
- len = redisFormatCommand(&cmd,"SET %b %b","foo",3,"b\0r",3);
+ len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3);
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
free(cmd);
test("Format command with %%b and an empty string: ");
- len = redisFormatCommand(&cmd,"SET %b %b","foo",3,"",0);
+ len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0);
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(0+2));
free(cmd);
@@ -177,7 +194,7 @@ static void test_format_commands(void) {
FLOAT_WIDTH_TEST(double);
test("Format command with invalid printf format: ");
- len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",3);
+ len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3);
test_cond(len == -1);
const char *argv[3];
@@ -200,10 +217,33 @@ static void test_format_commands(void) {
free(cmd);
}
+static void test_append_formatted_commands(struct config config) {
+ redisContext *c;
+ redisReply *reply;
+ char *cmd;
+ int len;
+
+ c = connect(config);
+
+ test("Append format command: ");
+
+ len = redisFormatCommand(&cmd, "SET foo bar");
+
+ test_cond(redisAppendFormattedCommand(c, cmd, len) == REDIS_OK);
+
+ assert(redisGetReply(c, (void*)&reply) == REDIS_OK);
+
+ free(cmd);
+ freeReplyObject(reply);
+
+ disconnect(c, 0);
+}
+
static void test_reply_reader(void) {
redisReader *reader;
void *reply;
int ret;
+ int i;
test("Error handling in reply parser: ");
reader = redisReaderCreate();
@@ -225,12 +265,13 @@ static void test_reply_reader(void) {
strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0);
redisReaderFree(reader);
- test("Set error on nested multi bulks with depth > 2: ");
+ test("Set error on nested multi bulks with depth > 7: ");
reader = redisReaderCreate();
- redisReaderFeed(reader,(char*)"*1\r\n",4);
- redisReaderFeed(reader,(char*)"*1\r\n",4);
- redisReaderFeed(reader,(char*)"*1\r\n",4);
- redisReaderFeed(reader,(char*)"*1\r\n",4);
+
+ for (i = 0; i < 9; i++) {
+ redisReaderFeed(reader,(char*)"*1\r\n",4);
+ }
+
ret = redisReaderGetReply(reader,NULL);
test_cond(ret == REDIS_ERR &&
strncasecmp(reader->errstr,"No support for",14) == 0);
@@ -284,7 +325,10 @@ static void test_blocking_connection_errors(void) {
c = redisConnect((char*)"idontexist.local", 6379);
test_cond(c->err == REDIS_ERR_OTHER &&
(strcmp(c->errstr,"Name or service not known") == 0 ||
- strcmp(c->errstr,"Can't resolve: idontexist.local") == 0));
+ strcmp(c->errstr,"Can't resolve: idontexist.local") == 0 ||
+ strcmp(c->errstr,"nodename nor servname provided, or not known") == 0 ||
+ strcmp(c->errstr,"No address associated with hostname") == 0 ||
+ strcmp(c->errstr,"no address associated with name") == 0));
redisFree(c);
test("Returns error when the port is not open: ");
@@ -326,7 +370,7 @@ static void test_blocking_connection(struct config config) {
freeReplyObject(reply);
test("%%b String interpolation works: ");
- reply = redisCommand(c,"SET %b %b","foo",3,"hello\x00world",11);
+ reply = redisCommand(c,"SET %b %b","foo",(size_t)3,"hello\x00world",(size_t)11);
freeReplyObject(reply);
reply = redisCommand(c,"GET foo");
test_cond(reply->type == REDIS_REPLY_STRING &&
@@ -374,7 +418,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) {
@@ -428,6 +472,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;
@@ -490,7 +558,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;
@@ -603,6 +671,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);
@@ -621,6 +690,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);
@@ -636,6 +707,8 @@ int main(int argc, char **argv) {
cfg.type = CONN_TCP;
test_blocking_connection(cfg);
test_blocking_io_errors(cfg);
+ test_invalid_timeout_errors(cfg);
+ test_append_formatted_commands(cfg);
if (throughput) test_throughput(cfg);
printf("\nTesting against Unix socket connection (%s):\n", cfg.unix.path);
@@ -644,6 +717,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;
diff --git a/deps/hiredis/zmalloc.h b/deps/hiredis/zmalloc.h
deleted file mode 100644
index 99b87ace9..000000000
--- a/deps/hiredis/zmalloc.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Drop in replacement for zmalloc.h in order to just use libc malloc without
- * any wrappering. */
-
-#ifndef ZMALLOC_H
-#define ZMALLOC_H
-
-#define zmalloc malloc
-#define zrealloc realloc
-#define zcalloc(x) calloc(x,1)
-#define zfree free
-#define zstrdup strdup
-
-#endif