Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
021321e0
Commit
021321e0
authored
Dec 16, 2010
by
Pieter Noordhuis
Browse files
Update hiredis to 0.9.2
parent
59aee551
Changes
16
Show whitespace changes
Inline
Side-by-side
deps/hiredis/Makefile
View file @
021321e0
...
...
@@ -6,31 +6,34 @@ OBJ = net.o hiredis.o sds.o async.o
BINS
=
hiredis-example hiredis-test
uname_S
:=
$(
shell
sh
-c
'uname -s 2>/dev/null || echo not'
)
OPTIMIZATION
?=
-O
2
OPTIMIZATION
?=
-O
3
ifeq
($(uname_S),SunOS)
CFLAGS
?=
-std
=
c99
-pedantic
$(OPTIMIZATION)
-fPIC
-Wall
-W
-D__EXTENSIONS__
-D_XPG6
CCLINK
?=
-ldl
-lnsl
-lsocket
-lm
-lpthread
CFLAGS
?=
-std
=
c99
-pedantic
$(OPTIMIZATION)
-fPIC
-Wall
-W
-D__EXTENSIONS__
-D_XPG6
$(ARCH)
$(PROF)
CCLINK
?=
-ldl
-lnsl
-lsocket
-lm
-lpthread
LDFLAGS
?=
-L
.
-Wl
,-R,.
DYLIBNAME
?=
libhiredis.so
DYLIB_MAKE_CMD
?=
gcc
-shared
-Wl
,-soname,
${DYLIBNAME}
-o
${DYLIBNAME}
${OBJ}
DYLIB_MAKE_CMD
?=
$(CC)
-G
-o
${DYLIBNAME}
${OBJ}
STLIBNAME
?=
libhiredis.a
STLIB_MAKE_CMD
?=
ar rcs
${STLIBNAME}
${OBJ}
else
ifeq
($(uname_S),Darwin)
CFLAGS
?=
-std
=
c99
-pedantic
$(OPTIMIZATION)
-fPIC
-Wall
-W
-Wwrite-strings
$(ARCH)
$(PROF)
CCLINK
?=
-lm
-pthread
OBJARCH
?=
-arch
i386
-arch
x86_64
CFLAGS
?=
-std
=
c99
-pedantic
$(OPTIMIZATION)
-fPIC
-Wall
-W
-Wwrite-strings
$(ARCH)
$(PROF)
CCLINK
?=
-lm
-pthread
LDFLAGS
?=
-L
.
-Wl
,-rpath,.
OBJARCH
?=
-arch
i386
-arch
x86_64
DYLIBNAME
?=
libhiredis.dylib
DYLIB_MAKE_CMD
?=
libtool
-dynamic
-o
${DYLIBNAME}
-lm
${DEBUG}
-
${OBJ}
STLIBNAME
?=
libhiredis.a
STLIB_MAKE_CMD
?=
libtool
-static
-o
${STLIBNAME}
-
${OBJ}
else
CFLAGS
?=
-std
=
c99
-pedantic
$(OPTIMIZATION)
-fPIC
-Wall
-W
-Wwrite-strings
$(ARCH)
$(PROF)
CCLINK
?=
-lm
-pthread
CFLAGS
?=
-std
=
c99
-pedantic
$(OPTIMIZATION)
-fPIC
-Wall
-W
-Wwrite-strings
$(ARCH)
$(PROF)
CCLINK
?=
-lm
-pthread
LDFLAGS
?=
-L
.
-Wl
,-rpath,.
DYLIBNAME
?=
libhiredis.so
DYLIB_MAKE_CMD
?=
gcc
-shared
-Wl
,-soname,
${DYLIBNAME}
-o
${DYLIBNAME}
${OBJ}
STLIBNAME
?=
libhiredis.a
STLIB_MAKE_CMD
?=
ar rcs
${STLIBNAME}
${OBJ}
endif
CCOPT
=
$(CFLAGS)
$(CCLINK)
$(ARCH)
$(PROF)
CCOPT
=
$(CFLAGS)
$(CCLINK)
DEBUG
?=
-g
-ggdb
PREFIX
?=
/usr/local
...
...
@@ -43,8 +46,6 @@ all: ${DYLIBNAME} ${BINS}
# Deps (use make dep to generate this)
net.o
:
net.c fmacros.h net.h
async.o
:
async.c async.h hiredis.h sds.h util.h
example-libev.o
:
example-libev.c hiredis.h async.h adapters/libev.h
example-libevent.o
:
example-libevent.c hiredis.h async.h adapters/libevent.h
example.o
:
example.c hiredis.h
hiredis.o
:
hiredis.c hiredis.h net.h sds.h util.h
sds.o
:
sds.c sds.h
...
...
@@ -60,14 +61,23 @@ dynamic: ${DYLIBNAME}
static
:
${STLIBNAME}
# Binaries:
hiredis-example-libevent
:
example-libevent.o ${DYLIBNAME}
$(CC)
-o
$@
$(CCOPT)
$(DEBUG)
-L
.
-lhiredis
-levent
-Wl
,-rpath,. example-libevent.c
hiredis-example-libevent
:
example-libevent.c adapters/libevent.h ${DYLIBNAME}
$(CC)
-o
$@
$(CCOPT)
$(DEBUG)
$(LDFLAGS)
-lhiredis
-levent
example-libevent.c
hiredis-example-libev
:
example-libev.c adapters/libev.h ${DYLIBNAME}
$(CC)
-o
$@
$(CCOPT)
$(DEBUG)
$(LDFLAGS)
-lhiredis
-lev
example-libev.c
hiredis-example-libev
:
example-libev.o ${DYLIBNAME}
$(CC)
-o
$@
$(CCOPT)
$(DEBUG)
-L
.
-lhiredis
-lev
-Wl
,-rpath,. example-libev.c
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 ${DYLIBNAME}
$(CC)
-o
$@
$(CCOPT)
$(DEBUG)
-I
$(AE_DIR)
$(LDFLAGS)
-lhiredis
example-ae.c
$(AE_DIR)
/ae.o
$(AE_DIR)
/zmalloc.o
endif
hiredis-%
:
%.o ${DYLIBNAME}
$(CC)
-o
$@
$(CCOPT)
$(DEBUG)
-L
.
-lhiredis
-Wl
,-rpath,.
$<
$(CC)
-o
$@
$(CCOPT)
$(DEBUG)
$(LDFLAGS)
-lhiredis
$<
test
:
hiredis-test
./hiredis-test
...
...
deps/hiredis/README.md
View file @
021321e0
...
...
@@ -35,15 +35,17 @@ To consume the synchronous API, there are only a few function calls that need to
### Connecting
The function
`redisConnect`
is used to create a so-called
`redisContext`
. The context is where
Hiredis holds state for a connection. The
`redisContext`
struct has an
`error`
field that is
non-NULL when the connection is in an error state. It contains a string with a textual
representation of the error. After trying to connect to Redis using
`redisConnect`
you should
check the
`error`
field to see if establishing the connection was successful:
The function
`redisConnect`
is used to create a so-called
`redisContext`
. The
context is where Hiredis holds state for a connection. The
`redisContext`
struct has an integer
`err`
field that is non-zero when an the connection is in
an error state. The field
`errstr`
will contain a string with a description of
the error. More information on errors can be found in the
**Errors**
section.
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
or != NULL
) {
printf("Error: %s\n", c->err
o
r);
if (c->err) {
printf("Error: %s\n", c->err
st
r);
// handle error
}
...
...
@@ -76,8 +78,8 @@ anywhere in an argument:
### Using replies
The return value of
`redisCommand`
holds a reply when the command was
successfully executed. When the return value is
`NULL`
, the
`error`
fiel
d
in the context
can
be
u
se
d to find out what was the cause of failure
.
successfully executed. When
an error occurs,
the return value is
`NULL`
an
d
the
`err`
field
in the context
will
be se
t (see section on
**Errors**
)
.
Once an error is returned the context cannot be reused and you should set up
a new connection.
...
...
@@ -166,7 +168,7 @@ to the `redisCommand` family, apart from not returning a reply:
After calling either function one or more times,
`redisGetReply`
can be used to receive the
subsequent replies. The return value for this function is either
`REDIS_OK`
or
`REDIS_ERR`
, where
the latter means an error occurred while reading a reply. Just as with the other commands,
the
`err
or
`
field in the context can be used to find out what the cause of this error is.
the
`err`
field in the context can be used to find out what the cause of this error is.
The following examples shows a simple pipeline (resulting in only a single call to
`write(2)`
and
a single call to
`write(2)`
):
...
...
@@ -188,6 +190,31 @@ This API can also be used to implement a blocking subscriber:
freeReplyObject(reply);
}
### Errors
When a function call is not successful, depending on the function either
`NULL`
or
`REDIS_ERR`
is
returned. The
`err`
field inside the context will be non-zero and set to one of the
following constants:
*
**`REDIS_ERR_IO`**
:
There was an I/O error while creating the connection, trying to write
to the socket or read from the socket. If you included
`errno.h`
in your
application, you can use the global
`errno`
variable to find out what is
wrong.
*
**`REDIS_ERR_EOF`**
:
The server closed the connection which resulted in an empty read.
*
**`REDIS_ERR_PROTOCOL`**
:
There was an error while parsing the protocol.
*
**`REDIS_ERR_OTHER`**
:
Any other error. Currently, it is only used when a specified hostname to connect
to cannot be resolved.
In every case, the
`errstr`
field in the context will be set to hold a string representation
of the error.
## Asynchronous API
Hiredis comes with an asynchronous API that works easily with any event library.
...
...
@@ -197,14 +224,14 @@ and [libevent](http://monkey.org/~provos/libevent/).
### Connecting
The function
`redisAsyncConnect`
can be used to establish a non-blocking connection to
Redis. It returns a pointer to the newly created
`redisAsyncContext`
struct. The
`err
or
`
field
Redis. It returns a pointer to the newly created
`redisAsyncContext`
struct. The
`err`
field
should be checked after creation to see if there were errors creating the connection.
Because the connection that will be created is non-blocking, the kernel is not able to
instantly return if the specified host and port is able to accept a connection.
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err
or != NULL
) {
printf("Error: %s\n", c->err
o
r);
if (c->err) {
printf("Error: %s\n", c->err
st
r);
// handle error
}
...
...
@@ -215,7 +242,7 @@ have the following prototype:
void(const redisAsyncContext *c, int status);
On a disconnect, the
`status`
argument is set to
`REDIS_OK`
when disconnection was initiated by the
user, or
`REDIS_ERR`
when the disconnection was caused by an error. When it is
`REDIS_ERR`
, the
`err
or
`
user, or
`REDIS_ERR`
when the disconnection was caused by an error. When it is
`REDIS_ERR`
, the
`err`
field in the context can be accessed to find out the cause of the error.
The context object is always free'd after the disconnect callback fired. When a reconnect is needed,
...
...
deps/hiredis/adapters/ae.h
0 → 100644
View file @
021321e0
#include <sys/types.h>
#include <ae.h>
#include "../hiredis.h"
#include "../async.h"
typedef
struct
redisAeEvents
{
redisAsyncContext
*
context
;
aeEventLoop
*
loop
;
int
fd
;
int
reading
,
writing
;
}
redisAeEvents
;
void
redisAeReadEvent
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
)
{
((
void
)
el
);
((
void
)
fd
);
((
void
)
mask
);
redisAeEvents
*
e
=
(
redisAeEvents
*
)
privdata
;
redisAsyncHandleRead
(
e
->
context
);
}
void
redisAeWriteEvent
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
)
{
((
void
)
el
);
((
void
)
fd
);
((
void
)
mask
);
redisAeEvents
*
e
=
(
redisAeEvents
*
)
privdata
;
redisAsyncHandleWrite
(
e
->
context
);
}
void
redisAeAddRead
(
void
*
privdata
)
{
redisAeEvents
*
e
=
(
redisAeEvents
*
)
privdata
;
aeEventLoop
*
loop
=
e
->
loop
;
if
(
!
e
->
reading
)
{
e
->
reading
=
1
;
aeCreateFileEvent
(
loop
,
e
->
fd
,
AE_READABLE
,
redisAeReadEvent
,
e
);
}
}
void
redisAeDelRead
(
void
*
privdata
)
{
redisAeEvents
*
e
=
(
redisAeEvents
*
)
privdata
;
aeEventLoop
*
loop
=
e
->
loop
;
if
(
e
->
reading
)
{
e
->
reading
=
0
;
aeDeleteFileEvent
(
loop
,
e
->
fd
,
AE_READABLE
);
}
}
void
redisAeAddWrite
(
void
*
privdata
)
{
redisAeEvents
*
e
=
(
redisAeEvents
*
)
privdata
;
aeEventLoop
*
loop
=
e
->
loop
;
if
(
!
e
->
writing
)
{
e
->
writing
=
1
;
aeCreateFileEvent
(
loop
,
e
->
fd
,
AE_WRITABLE
,
redisAeWriteEvent
,
e
);
}
}
void
redisAeDelWrite
(
void
*
privdata
)
{
redisAeEvents
*
e
=
(
redisAeEvents
*
)
privdata
;
aeEventLoop
*
loop
=
e
->
loop
;
if
(
e
->
writing
)
{
e
->
writing
=
0
;
aeDeleteFileEvent
(
loop
,
e
->
fd
,
AE_WRITABLE
);
}
}
void
redisAeCleanup
(
void
*
privdata
)
{
redisAeEvents
*
e
=
(
redisAeEvents
*
)
privdata
;
redisAeDelRead
(
privdata
);
redisAeDelWrite
(
privdata
);
free
(
e
);
}
int
redisAeAttach
(
aeEventLoop
*
loop
,
redisAsyncContext
*
ac
)
{
redisContext
*
c
=
&
(
ac
->
c
);
redisAeEvents
*
e
;
/* Nothing should be attached when something is already attached */
if
(
ac
->
_adapter_data
!=
NULL
)
return
REDIS_ERR
;
/* Create container for context and r/w events */
e
=
(
redisAeEvents
*
)
malloc
(
sizeof
(
*
e
));
e
->
context
=
ac
;
e
->
loop
=
loop
;
e
->
fd
=
c
->
fd
;
e
->
reading
=
e
->
writing
=
0
;
/* Register functions to start/stop listening for events */
ac
->
evAddRead
=
redisAeAddRead
;
ac
->
evDelRead
=
redisAeDelRead
;
ac
->
evAddWrite
=
redisAeAddWrite
;
ac
->
evDelWrite
=
redisAeDelWrite
;
ac
->
evCleanup
=
redisAeCleanup
;
ac
->
_adapter_data
=
e
;
return
REDIS_OK
;
}
deps/hiredis/adapters/libev.h
View file @
021321e0
...
...
@@ -10,69 +10,89 @@ typedef struct redisLibevEvents {
ev_io
rev
,
wev
;
}
redisLibevEvents
;
void
redisLibevReadEvent
(
struct
ev_loop
*
loop
,
ev_io
*
watcher
,
int
revents
)
{
((
void
)
loop
);
((
void
)
revents
);
redisLibevEvents
*
e
=
watcher
->
data
;
void
redisLibevReadEvent
(
EV_P_
ev_io
*
watcher
,
int
revents
)
{
#if EV_MULTIPLICITY
((
void
)
loop
);
#endif
((
void
)
revents
);
redisLibevEvents
*
e
=
(
redisLibevEvents
*
)
watcher
->
data
;
redisAsyncHandleRead
(
e
->
context
);
}
void
redisLibevWriteEvent
(
struct
ev_loop
*
loop
,
ev_io
*
watcher
,
int
revents
)
{
((
void
)
loop
);
((
void
)
revents
);
redisLibevEvents
*
e
=
watcher
->
data
;
void
redisLibevWriteEvent
(
EV_P_
ev_io
*
watcher
,
int
revents
)
{
#if EV_MULTIPLICITY
((
void
)
loop
);
#endif
((
void
)
revents
);
redisLibevEvents
*
e
=
(
redisLibevEvents
*
)
watcher
->
data
;
redisAsyncHandleWrite
(
e
->
context
);
}
void
redisLibevAddRead
(
void
*
privdata
)
{
redisLibevEvents
*
e
=
privdata
;
redisLibevEvents
*
e
=
(
redisLibevEvents
*
)
privdata
;
struct
ev_loop
*
loop
=
e
->
loop
;
((
void
)
loop
);
if
(
!
e
->
reading
)
{
e
->
reading
=
1
;
ev_io_start
(
e
->
loop
,
&
e
->
rev
);
ev_io_start
(
EV_A_
&
e
->
rev
);
}
}
void
redisLibevDelRead
(
void
*
privdata
)
{
redisLibevEvents
*
e
=
privdata
;
redisLibevEvents
*
e
=
(
redisLibevEvents
*
)
privdata
;
struct
ev_loop
*
loop
=
e
->
loop
;
((
void
)
loop
);
if
(
e
->
reading
)
{
e
->
reading
=
0
;
ev_io_stop
(
e
->
loop
,
&
e
->
rev
);
ev_io_stop
(
EV_A_
&
e
->
rev
);
}
}
void
redisLibevAddWrite
(
void
*
privdata
)
{
redisLibevEvents
*
e
=
privdata
;
redisLibevEvents
*
e
=
(
redisLibevEvents
*
)
privdata
;
struct
ev_loop
*
loop
=
e
->
loop
;
((
void
)
loop
);
if
(
!
e
->
writing
)
{
e
->
writing
=
1
;
ev_io_start
(
e
->
loop
,
&
e
->
wev
);
ev_io_start
(
EV_A_
&
e
->
wev
);
}
}
void
redisLibevDelWrite
(
void
*
privdata
)
{
redisLibevEvents
*
e
=
privdata
;
redisLibevEvents
*
e
=
(
redisLibevEvents
*
)
privdata
;
struct
ev_loop
*
loop
=
e
->
loop
;
((
void
)
loop
);
if
(
e
->
writing
)
{
e
->
writing
=
0
;
ev_io_stop
(
e
->
loop
,
&
e
->
wev
);
ev_io_stop
(
EV_A_
&
e
->
wev
);
}
}
void
redisLibevCleanup
(
void
*
privdata
)
{
redisLibevEvents
*
e
=
privdata
;
redisLibevEvents
*
e
=
(
redisLibevEvents
*
)
privdata
;
redisLibevDelRead
(
privdata
);
redisLibevDelWrite
(
privdata
);
free
(
e
);
}
int
redisLibevAttach
(
redisAsyncContext
*
ac
,
struct
ev_loop
*
loop
)
{
int
redisLibevAttach
(
EV_P_
redisAsyncContext
*
ac
)
{
redisContext
*
c
=
&
(
ac
->
c
);
redisLibevEvents
*
e
;
/* Nothing should be attached when something is already attached */
if
(
ac
->
data
!=
NULL
)
if
(
ac
->
_adapter_
data
!=
NULL
)
return
REDIS_ERR
;
/* Create container for context and r/w events */
e
=
malloc
(
sizeof
(
*
e
));
e
=
(
redisLibevEvents
*
)
malloc
(
sizeof
(
*
e
));
e
->
context
=
ac
;
#if EV_MULTIPLICITY
e
->
loop
=
loop
;
#else
e
->
loop
=
NULL
;
#endif
e
->
reading
=
e
->
writing
=
0
;
e
->
rev
.
data
=
e
;
e
->
wev
.
data
=
e
;
...
...
@@ -83,10 +103,11 @@ int redisLibevAttach(redisAsyncContext *ac, struct ev_loop *loop) {
ac
->
evAddWrite
=
redisLibevAddWrite
;
ac
->
evDelWrite
=
redisLibevDelWrite
;
ac
->
evCleanup
=
redisLibevCleanup
;
ac
->
data
=
e
;
ac
->
_adapter_
data
=
e
;
/* Initialize read/write events */
ev_io_init
(
&
e
->
rev
,
redisLibevReadEvent
,
c
->
fd
,
EV_READ
);
ev_io_init
(
&
e
->
wev
,
redisLibevWriteEvent
,
c
->
fd
,
EV_WRITE
);
return
REDIS_OK
;
}
deps/hiredis/adapters/libevent.h
View file @
021321e0
...
...
@@ -10,38 +10,38 @@ typedef struct redisLibeventEvents {
void
redisLibeventReadEvent
(
int
fd
,
short
event
,
void
*
arg
)
{
((
void
)
fd
);
((
void
)
event
);
redisLibeventEvents
*
e
=
arg
;
redisLibeventEvents
*
e
=
(
redisLibeventEvents
*
)
arg
;
redisAsyncHandleRead
(
e
->
context
);
}
void
redisLibeventWriteEvent
(
int
fd
,
short
event
,
void
*
arg
)
{
((
void
)
fd
);
((
void
)
event
);
redisLibeventEvents
*
e
=
arg
;
redisLibeventEvents
*
e
=
(
redisLibeventEvents
*
)
arg
;
redisAsyncHandleWrite
(
e
->
context
);
}
void
redisLibeventAddRead
(
void
*
privdata
)
{
redisLibeventEvents
*
e
=
privdata
;
redisLibeventEvents
*
e
=
(
redisLibeventEvents
*
)
privdata
;
event_add
(
&
e
->
rev
,
NULL
);
}
void
redisLibeventDelRead
(
void
*
privdata
)
{
redisLibeventEvents
*
e
=
privdata
;
redisLibeventEvents
*
e
=
(
redisLibeventEvents
*
)
privdata
;
event_del
(
&
e
->
rev
);
}
void
redisLibeventAddWrite
(
void
*
privdata
)
{
redisLibeventEvents
*
e
=
privdata
;
redisLibeventEvents
*
e
=
(
redisLibeventEvents
*
)
privdata
;
event_add
(
&
e
->
wev
,
NULL
);
}
void
redisLibeventDelWrite
(
void
*
privdata
)
{
redisLibeventEvents
*
e
=
privdata
;
redisLibeventEvents
*
e
=
(
redisLibeventEvents
*
)
privdata
;
event_del
(
&
e
->
wev
);
}
void
redisLibeventCleanup
(
void
*
privdata
)
{
redisLibeventEvents
*
e
=
privdata
;
redisLibeventEvents
*
e
=
(
redisLibeventEvents
*
)
privdata
;
event_del
(
&
e
->
rev
);
event_del
(
&
e
->
wev
);
free
(
e
);
...
...
@@ -52,11 +52,11 @@ int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
redisLibeventEvents
*
e
;
/* Nothing should be attached when something is already attached */
if
(
ac
->
data
!=
NULL
)
if
(
ac
->
_adapter_
data
!=
NULL
)
return
REDIS_ERR
;
/* Create container for context and r/w events */
e
=
malloc
(
sizeof
(
*
e
));
e
=
(
redisLibeventEvents
*
)
malloc
(
sizeof
(
*
e
));
e
->
context
=
ac
;
/* Register functions to start/stop listening for events */
...
...
@@ -65,7 +65,7 @@ int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
ac
->
evAddWrite
=
redisLibeventAddWrite
;
ac
->
evDelWrite
=
redisLibeventDelWrite
;
ac
->
evCleanup
=
redisLibeventCleanup
;
ac
->
data
=
e
;
ac
->
_adapter_
data
=
e
;
/* Initialize and install read/write events */
event_set
(
&
e
->
rev
,
c
->
fd
,
EV_READ
,
redisLibeventReadEvent
,
e
);
...
...
deps/hiredis/async.c
View file @
021321e0
/*
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
...
...
@@ -38,8 +40,29 @@ void __redisAppendCommand(redisContext *c, char *cmd, size_t len);
static
redisAsyncContext
*
redisAsyncInitialize
(
redisContext
*
c
)
{
redisAsyncContext
*
ac
=
realloc
(
c
,
sizeof
(
redisAsyncContext
));
/* Set all bytes in the async part of the context to 0 */
memset
(
ac
+
sizeof
(
redisContext
),
0
,
sizeof
(
redisAsyncContext
)
-
sizeof
(
redisContext
));
c
=
&
(
ac
->
c
);
/* The regular connect functions will always set the flag REDIS_CONNECTED.
* For the async API, we want to wait until the first write event is
* received up before setting this flag, so reset it here. */
c
->
flags
&=
~
REDIS_CONNECTED
;
ac
->
err
=
0
;
ac
->
errstr
=
NULL
;
ac
->
data
=
NULL
;
ac
->
_adapter_data
=
NULL
;
ac
->
evAddRead
=
NULL
;
ac
->
evDelRead
=
NULL
;
ac
->
evAddWrite
=
NULL
;
ac
->
evDelWrite
=
NULL
;
ac
->
evCleanup
=
NULL
;
ac
->
onConnect
=
NULL
;
ac
->
onDisconnect
=
NULL
;
ac
->
replies
.
head
=
NULL
;
ac
->
replies
.
tail
=
NULL
;
return
ac
;
}
...
...
@@ -70,6 +93,14 @@ int redisAsyncSetReplyObjectFunctions(redisAsyncContext *ac, redisReplyObjectFun
return
redisSetReplyObjectFunctions
(
c
,
fn
);
}
int
redisAsyncSetConnectCallback
(
redisAsyncContext
*
ac
,
redisConnectCallback
*
fn
)
{
if
(
ac
->
onConnect
==
NULL
)
{
ac
->
onConnect
=
fn
;
return
REDIS_OK
;
}
return
REDIS_ERR
;
}
int
redisAsyncSetDisconnectCallback
(
redisAsyncContext
*
ac
,
redisDisconnectCallback
*
fn
)
{
if
(
ac
->
onDisconnect
==
NULL
)
{
ac
->
onDisconnect
=
fn
;
...
...
@@ -153,7 +184,7 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
}
/* Signal event lib to clean up */
if
(
ac
->
evCleanup
)
ac
->
evCleanup
(
ac
->
data
);
if
(
ac
->
evCleanup
)
ac
->
evCleanup
(
ac
->
_adapter_
data
);
/* Execute callback with proper status */
if
(
ac
->
onDisconnect
)
ac
->
onDisconnect
(
ac
,
status
);
...
...
@@ -206,7 +237,7 @@ void redisAsyncHandleRead(redisAsyncContext *ac) {
__redisAsyncDisconnect
(
ac
);
}
else
{
/* Always re-schedule reads */
if
(
ac
->
evAddRead
)
ac
->
evAddRead
(
ac
->
data
);
if
(
ac
->
evAddRead
)
ac
->
evAddRead
(
ac
->
_adapter_
data
);
redisProcessCallbacks
(
ac
);
}
}
...
...
@@ -220,13 +251,19 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) {
}
else
{
/* Continue writing when not done, stop writing otherwise */
if
(
!
done
)
{
if
(
ac
->
evAddWrite
)
ac
->
evAddWrite
(
ac
->
data
);
if
(
ac
->
evAddWrite
)
ac
->
evAddWrite
(
ac
->
_adapter_
data
);
}
else
{
if
(
ac
->
evDelWrite
)
ac
->
evDelWrite
(
ac
->
data
);
if
(
ac
->
evDelWrite
)
ac
->
evDelWrite
(
ac
->
_adapter_
data
);
}
/* Always schedule reads when something was written */
if
(
ac
->
evAddRead
)
ac
->
evAddRead
(
ac
->
data
);
/* Always schedule reads after writes */
if
(
ac
->
evAddRead
)
ac
->
evAddRead
(
ac
->
_adapter_data
);
/* Fire onConnect when this is the first write event. */
if
(
!
(
c
->
flags
&
REDIS_CONNECTED
))
{
c
->
flags
|=
REDIS_CONNECTED
;
if
(
ac
->
onConnect
)
ac
->
onConnect
(
ac
);
}
}
}
...
...
@@ -249,7 +286,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
__redisPushCallback
(
&
ac
->
replies
,
&
cb
);
/* Always schedule a write when the write buffer is non-empty */
if
(
ac
->
evAddWrite
)
ac
->
evAddWrite
(
ac
->
data
);
if
(
ac
->
evAddWrite
)
ac
->
evAddWrite
(
ac
->
_adapter_
data
);
return
REDIS_OK
;
}
...
...
deps/hiredis/async.h
View file @
021321e0
...
...
@@ -31,6 +31,10 @@
#define __HIREDIS_ASYNC_H
#include "hiredis.h"
#ifdef __cplusplus
extern
"C"
{
#endif
struct
redisAsyncContext
;
/* need forward declaration of redisAsyncContext */
/* Reply callback prototype and container */
...
...
@@ -46,8 +50,9 @@ typedef struct redisCallbackList {
redisCallback
*
head
,
*
tail
;
}
redisCallbackList
;
/*
Disc
onnect callback prototype */
/*
C
onnect
ion
callback prototype
s
*/
typedef
void
(
redisDisconnectCallback
)(
const
struct
redisAsyncContext
*
,
int
status
);
typedef
void
(
redisConnectCallback
)(
const
struct
redisAsyncContext
*
);
/* Context for an async connection to Redis */
typedef
struct
redisAsyncContext
{
...
...
@@ -58,6 +63,12 @@ typedef struct redisAsyncContext {
int
err
;
char
*
errstr
;
/* Not used by hiredis */
void
*
data
;
/* Used by the different event lib adapters to store their private data */
void
*
_adapter_data
;
/* Called when the library expects to start reading/writing.
* The supplied functions should be idempotent. */
void
(
*
evAddRead
)(
void
*
privdata
);
...
...
@@ -65,12 +76,14 @@ typedef struct redisAsyncContext {
void
(
*
evAddWrite
)(
void
*
privdata
);
void
(
*
evDelWrite
)(
void
*
privdata
);
void
(
*
evCleanup
)(
void
*
privdata
);
void
*
data
;
/* Called when either the connection is terminated due to an error or per
* user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
redisDisconnectCallback
*
onDisconnect
;
/* Called when the first write event was received. */
redisConnectCallback
*
onConnect
;
/* Reply callbacks */
redisCallbackList
replies
;
}
redisAsyncContext
;
...
...
@@ -78,6 +91,7 @@ typedef struct redisAsyncContext {
/* Functions that proxy to hiredis */
redisAsyncContext
*
redisAsyncConnect
(
const
char
*
ip
,
int
port
);
int
redisAsyncSetReplyObjectFunctions
(
redisAsyncContext
*
ac
,
redisReplyObjectFunctions
*
fn
);
int
redisAsyncSetConnectCallback
(
redisAsyncContext
*
ac
,
redisConnectCallback
*
fn
);
int
redisAsyncSetDisconnectCallback
(
redisAsyncContext
*
ac
,
redisDisconnectCallback
*
fn
);
void
redisAsyncDisconnect
(
redisAsyncContext
*
ac
);
...
...
@@ -91,4 +105,8 @@ int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdat
int
redisAsyncCommand
(
redisAsyncContext
*
ac
,
redisCallbackFn
*
fn
,
void
*
privdata
,
const
char
*
format
,
...);
int
redisAsyncCommandArgv
(
redisAsyncContext
*
ac
,
redisCallbackFn
*
fn
,
void
*
privdata
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
#ifdef __cplusplus
}
#endif
#endif
deps/hiredis/example-ae.c
0 → 100644
View file @
021321e0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.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
;
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
)
{
((
void
)
c
);
printf
(
"connected...
\n
"
);
}
void
disconnectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
if
(
status
!=
REDIS_OK
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
}
printf
(
"disconnected...
\n
"
);
aeStop
(
loop
);
}
int
main
(
int
argc
,
char
**
argv
)
{
signal
(
SIGPIPE
,
SIG_IGN
);
redisAsyncContext
*
c
=
redisAsyncConnect
(
"127.0.0.1"
,
6379
);
if
(
c
->
err
)
{
/* Let *c leak for now... */
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
1
;
}
loop
=
aeCreateEventLoop
();
redisAeAttach
(
loop
,
c
);
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"
);
aeMain
(
loop
);
return
0
;
}
deps/hiredis/example-libev.c
View file @
021321e0
...
...
@@ -15,15 +15,20 @@ void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisAsyncDisconnect
(
c
);
}
void
connectCallback
(
const
redisAsyncContext
*
c
)
{
((
void
)
c
);
printf
(
"connected...
\n
"
);
}
void
disconnectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
if
(
status
!=
REDIS_OK
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
}
printf
(
"disconnected...
\n
"
);
}
int
main
(
int
argc
,
char
**
argv
)
{
signal
(
SIGPIPE
,
SIG_IGN
);
struct
ev_loop
*
loop
=
ev_default_loop
(
0
);
redisAsyncContext
*
c
=
redisAsyncConnect
(
"127.0.0.1"
,
6379
);
if
(
c
->
err
)
{
...
...
@@ -32,10 +37,11 @@ int main (int argc, char **argv) {
return
1
;
}
redisLibevAttach
(
c
,
loop
);
redisLibevAttach
(
EV_DEFAULT_
c
);
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"
);
ev_loop
(
loop
,
0
);
ev_loop
(
EV_DEFAULT_
0
);
return
0
;
}
deps/hiredis/example-libevent.c
View file @
021321e0
...
...
@@ -15,10 +15,16 @@ void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisAsyncDisconnect
(
c
);
}
void
connectCallback
(
const
redisAsyncContext
*
c
)
{
((
void
)
c
);
printf
(
"connected...
\n
"
);
}
void
disconnectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
if
(
status
!=
REDIS_OK
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
}
printf
(
"disconnected...
\n
"
);
}
int
main
(
int
argc
,
char
**
argv
)
{
...
...
@@ -33,6 +39,7 @@ int main (int argc, char **argv) {
}
redisLibeventAttach
(
c
,
base
);
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"
);
...
...
deps/hiredis/example.c
View file @
021321e0
...
...
@@ -17,7 +17,7 @@ int main(void) {
/* PING server */
reply
=
redisCommand
(
c
,
"PING"
);
printf
(
"P
O
NG: %s
\n
"
,
reply
->
str
);
printf
(
"P
I
NG: %s
\n
"
,
reply
->
str
);
freeReplyObject
(
reply
);
/* Set a key */
...
...
deps/hiredis/hiredis.c
View file @
021321e0
/*
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
...
...
@@ -32,6 +34,7 @@
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#include "hiredis.h"
#include "net.h"
...
...
@@ -44,10 +47,12 @@ typedef struct redisReader {
void
*
reply
;
/* holds temporary reply */
sds
buf
;
/* read buffer */
unsigned
int
pos
;
/* buffer cursor */
size_t
pos
;
/* buffer cursor */
size_t
len
;
/* buffer length */
redisReadTask
rstack
[
3
];
/* stack of read tasks */
int
ridx
;
/* index of stack */
void
*
privdata
;
/* user-settable arbitrary field */
}
redisReader
;
static
redisReply
*
createReplyObject
(
int
type
);
...
...
@@ -68,7 +73,7 @@ static redisReplyObjectFunctions defaultFunctions = {
/* Create a reply object */
static
redisReply
*
createReplyObject
(
int
type
)
{
redisReply
*
r
=
c
alloc
(
sizeof
(
*
r
)
,
1
);
redisReply
*
r
=
m
alloc
(
sizeof
(
*
r
));
if
(
!
r
)
redisOOM
();
r
->
type
=
type
;
...
...
@@ -88,8 +93,9 @@ void freeReplyObject(void *reply) {
if
(
r
->
element
[
j
])
freeReplyObject
(
r
->
element
[
j
]);
free
(
r
->
element
);
break
;
default:
if
(
r
->
str
!=
NULL
)
case
REDIS_REPLY_ERROR
:
case
REDIS_REPLY_STATUS
:
case
REDIS_REPLY_STRING
:
free
(
r
->
str
);
break
;
}
...
...
@@ -111,7 +117,7 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
r
->
len
=
len
;
if
(
task
->
parent
)
{
redisReply
*
parent
=
task
->
parent
;
redisReply
*
parent
=
task
->
parent
->
obj
;
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
);
parent
->
element
[
task
->
idx
]
=
r
;
}
...
...
@@ -124,7 +130,7 @@ static void *createArrayObject(const redisReadTask *task, int elements) {
if
((
r
->
element
=
calloc
(
sizeof
(
redisReply
*
),
elements
))
==
NULL
)
redisOOM
();
if
(
task
->
parent
)
{
redisReply
*
parent
=
task
->
parent
;
redisReply
*
parent
=
task
->
parent
->
obj
;
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
);
parent
->
element
[
task
->
idx
]
=
r
;
}
...
...
@@ -135,7 +141,7 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
redisReply
*
r
=
createReplyObject
(
REDIS_REPLY_INTEGER
);
r
->
integer
=
value
;
if
(
task
->
parent
)
{
redisReply
*
parent
=
task
->
parent
;
redisReply
*
parent
=
task
->
parent
->
obj
;
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
);
parent
->
element
[
task
->
idx
]
=
r
;
}
...
...
@@ -145,7 +151,7 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
static
void
*
createNilObject
(
const
redisReadTask
*
task
)
{
redisReply
*
r
=
createReplyObject
(
REDIS_REPLY_NIL
);
if
(
task
->
parent
)
{
redisReply
*
parent
=
task
->
parent
;
redisReply
*
parent
=
task
->
parent
->
obj
;
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
);
parent
->
element
[
task
->
idx
]
=
r
;
}
...
...
@@ -154,7 +160,7 @@ static void *createNilObject(const redisReadTask *task) {
static
char
*
readBytes
(
redisReader
*
r
,
unsigned
int
bytes
)
{
char
*
p
;
if
(
sdslen
(
r
->
buf
)
-
r
->
pos
>=
bytes
)
{
if
(
r
->
len
-
r
->
pos
>=
bytes
)
{
p
=
r
->
buf
+
r
->
pos
;
r
->
pos
+=
bytes
;
return
p
;
...
...
@@ -162,20 +168,60 @@ static char *readBytes(redisReader *r, unsigned int bytes) {
return
NULL
;
}
static
char
*
seekNewline
(
char
*
s
)
{
/* Find pointer to \r\n without strstr */
while
(
s
!=
NULL
)
{
s
=
strchr
(
s
,
'\r'
);
if
(
s
!=
NULL
)
{
if
(
s
[
1
]
==
'\n'
)
break
;
else
/* Find pointer to \r\n. */
static
char
*
seekNewline
(
char
*
s
,
size_t
len
)
{
int
pos
=
0
;
int
_len
=
len
-
1
;
/* Position should be < len-1 because the character at "pos" should be
* followed by a \n. Note that strchr cannot be used because it doesn't
* allow to search a limited length and the buffer that is being searched
* might not have a trailing NULL character. */
while
(
pos
<
_len
)
{
while
(
pos
<
_len
&&
s
[
pos
]
!=
'\r'
)
pos
++
;
if
(
s
[
pos
]
!=
'\r'
)
{
/* Not found. */
return
NULL
;
}
else
{
if
(
s
[
pos
+
1
]
==
'\n'
)
{
/* Found. */
return
s
+
pos
;
}
else
{
/* Continue searching. */
pos
++
;
}
}
}
return
NULL
;
}
/* Read a long long value starting at *s, under the assumption that it will be
* terminated by \r\n. Ambiguously returns -1 for unexpected input. */
static
long
long
readLongLong
(
char
*
s
)
{
long
long
v
=
0
;
int
dec
,
mult
=
1
;
char
c
;
if
(
*
s
==
'-'
)
{
mult
=
-
1
;
s
++
;
}
else
if
(
*
s
==
'+'
)
{
mult
=
1
;
s
++
;
}
while
((
c
=
*
(
s
++
))
!=
'\r'
)
{
dec
=
c
-
'0'
;
if
(
dec
>=
0
&&
dec
<
10
)
{
v
*=
10
;
v
+=
dec
;
}
else
{
break
;
/* Should not happen... */
return
-
1
;
}
}
return
s
;
return
mult
*
v
;
}
static
char
*
readLine
(
redisReader
*
r
,
int
*
_len
)
{
...
...
@@ -183,7 +229,7 @@ static char *readLine(redisReader *r, int *_len) {
int
len
;
p
=
r
->
buf
+
r
->
pos
;
s
=
seekNewline
(
p
);
s
=
seekNewline
(
p
,(
r
->
len
-
r
->
pos
)
);
if
(
s
!=
NULL
)
{
len
=
s
-
(
r
->
buf
+
r
->
pos
);
r
->
pos
+=
len
+
2
;
/* skip \r\n */
...
...
@@ -227,7 +273,7 @@ static int processLineItem(redisReader *r) {
if
((
p
=
readLine
(
r
,
&
len
))
!=
NULL
)
{
if
(
r
->
fn
)
{
if
(
cur
->
type
==
REDIS_REPLY_INTEGER
)
{
obj
=
r
->
fn
->
createInteger
(
cur
,
strtoll
(
p
,
NULL
,
10
));
obj
=
r
->
fn
->
createInteger
(
cur
,
readLongLong
(
p
));
}
else
{
obj
=
r
->
fn
->
createString
(
cur
,
p
,
len
);
}
...
...
@@ -235,9 +281,8 @@ static int processLineItem(redisReader *r) {
obj
=
(
void
*
)(
size_t
)(
cur
->
type
);
}
/* If there is no root yet, register this object as root. */
if
(
r
->
reply
==
NULL
)
r
->
reply
=
obj
;
/* Set reply if this is the root object. */
if
(
r
->
ridx
==
0
)
r
->
reply
=
obj
;
moveToNextTask
(
r
);
return
0
;
}
...
...
@@ -250,32 +295,36 @@ static int processBulkItem(redisReader *r) {
char
*
p
,
*
s
;
long
len
;
unsigned
long
bytelen
;
int
success
=
0
;
p
=
r
->
buf
+
r
->
pos
;
s
=
seekNewline
(
p
);
s
=
seekNewline
(
p
,
r
->
len
-
r
->
pos
);
if
(
s
!=
NULL
)
{
p
=
r
->
buf
+
r
->
pos
;
bytelen
=
s
-
(
r
->
buf
+
r
->
pos
)
+
2
;
/* include \r\n */
len
=
strtol
(
p
,
NULL
,
10
);
len
=
readLongLong
(
p
);
if
(
len
<
0
)
{
/* The nil object can always be created. */
obj
=
r
->
fn
?
r
->
fn
->
createNil
(
cur
)
:
(
void
*
)
REDIS_REPLY_NIL
;
success
=
1
;
}
else
{
/* Only continue when the buffer contains the entire bulk item. */
bytelen
+=
len
+
2
;
/* include \r\n */
if
(
r
->
pos
+
bytelen
<=
sdslen
(
r
->
buf
)
)
{
if
(
r
->
pos
+
bytelen
<=
r
->
len
)
{
obj
=
r
->
fn
?
r
->
fn
->
createString
(
cur
,
s
+
2
,
len
)
:
(
void
*
)
REDIS_REPLY_STRING
;
success
=
1
;
}
}
/* Proceed when obj was created. */
if
(
obj
!=
NULL
)
{
if
(
success
)
{
r
->
pos
+=
bytelen
;
if
(
r
->
reply
==
NULL
)
r
->
reply
=
obj
;
/* Set reply if this is the root object. */
if
(
r
->
ridx
==
0
)
r
->
reply
=
obj
;
moveToNextTask
(
r
);
return
0
;
}
...
...
@@ -288,9 +337,19 @@ static int processMultiBulkItem(redisReader *r) {
void
*
obj
;
char
*
p
;
long
elements
;
int
root
=
0
;
/* Set error for nested multi bulks with depth > 1 */
if
(
r
->
ridx
==
2
)
{
redisSetReplyReaderError
(
r
,
sdscatprintf
(
sdsempty
(),
"No support for nested multi bulk replies with depth > 1"
));
return
-
1
;
}
if
((
p
=
readLine
(
r
,
NULL
))
!=
NULL
)
{
elements
=
strtol
(
p
,
NULL
,
10
);
elements
=
readLongLong
(
p
);
root
=
(
r
->
ridx
==
0
);
if
(
elements
==
-
1
)
{
obj
=
r
->
fn
?
r
->
fn
->
createNil
(
cur
)
:
(
void
*
)
REDIS_REPLY_NIL
;
...
...
@@ -302,19 +361,21 @@ static int processMultiBulkItem(redisReader *r) {
/* Modify task stack when there are more than 0 elements. */
if
(
elements
>
0
)
{
cur
->
elements
=
elements
;
cur
->
obj
=
obj
;
r
->
ridx
++
;
r
->
rstack
[
r
->
ridx
].
type
=
-
1
;
r
->
rstack
[
r
->
ridx
].
elements
=
-
1
;
r
->
rstack
[
r
->
ridx
].
parent
=
obj
;
r
->
rstack
[
r
->
ridx
].
idx
=
0
;
r
->
rstack
[
r
->
ridx
].
obj
=
NULL
;
r
->
rstack
[
r
->
ridx
].
parent
=
cur
;
r
->
rstack
[
r
->
ridx
].
privdata
=
r
->
privdata
;
}
else
{
moveToNextTask
(
r
);
}
}
/* Object was created, so we can always continue. */
if
(
r
->
reply
==
NULL
)
r
->
reply
=
obj
;
/* Set reply if this is the root object. */
if
(
root
)
r
->
reply
=
obj
;
return
0
;
}
return
-
1
;
...
...
@@ -347,7 +408,7 @@ static int processItem(redisReader *r) {
default:
byte
=
sdscatrepr
(
sdsempty
(),
p
,
1
);
redisSetReplyReaderError
(
r
,
sdscatprintf
(
sdsempty
(),
"
p
rotocol error, got %s as reply type byte"
,
byte
));
"
P
rotocol error, got %s as reply type byte"
,
byte
));
sdsfree
(
byte
);
return
-
1
;
}
...
...
@@ -368,8 +429,7 @@ static int processItem(redisReader *r) {
case
REDIS_REPLY_ARRAY
:
return
processMultiBulkItem
(
r
);
default:
redisSetReplyReaderError
(
r
,
sdscatprintf
(
sdsempty
(),
"unknown item type '%d'"
,
cur
->
type
));
assert
(
NULL
);
return
-
1
;
}
}
...
...
@@ -394,6 +454,17 @@ int redisReplyReaderSetReplyObjectFunctions(void *reader, redisReplyObjectFuncti
return
REDIS_ERR
;
}
/* Set the private data field that is used in the read tasks. This argument can
* be used to curry arbitrary data to the custom reply object functions. */
int
redisReplyReaderSetPrivdata
(
void
*
reader
,
void
*
privdata
)
{
redisReader
*
r
=
reader
;
if
(
r
->
reply
==
NULL
)
{
r
->
privdata
=
privdata
;
return
REDIS_OK
;
}
return
REDIS_ERR
;
}
/* External libraries wrapping hiredis might need access to the temporary
* variable while the reply is built up. When the reader contains an
* object in between receiving some bytes to parse, this object might
...
...
@@ -437,8 +508,10 @@ void redisReplyReaderFeed(void *reader, char *buf, size_t len) {
redisReader
*
r
=
reader
;
/* Copy the provided buffer. */
if
(
buf
!=
NULL
&&
len
>=
1
)
if
(
buf
!=
NULL
&&
len
>=
1
)
{
r
->
buf
=
sdscatlen
(
r
->
buf
,
buf
,
len
);
r
->
len
=
sdslen
(
r
->
buf
);
}
}
int
redisReplyReaderGetReply
(
void
*
reader
,
void
**
reply
)
{
...
...
@@ -446,15 +519,17 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
if
(
reply
!=
NULL
)
*
reply
=
NULL
;
/* When the buffer is empty, there will never be a reply. */
if
(
sdslen
(
r
->
buf
)
==
0
)
if
(
r
->
len
==
0
)
return
REDIS_OK
;
/* Set first item to process when the stack is empty. */
if
(
r
->
ridx
==
-
1
)
{
r
->
rstack
[
0
].
type
=
-
1
;
r
->
rstack
[
0
].
elements
=
-
1
;
r
->
rstack
[
0
].
parent
=
NULL
;
r
->
rstack
[
0
].
idx
=
-
1
;
r
->
rstack
[
0
].
obj
=
NULL
;
r
->
rstack
[
0
].
parent
=
NULL
;
r
->
rstack
[
0
].
privdata
=
r
->
privdata
;
r
->
ridx
=
0
;
}
...
...
@@ -465,14 +540,15 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
/* Discard the consumed part of the buffer. */
if
(
r
->
pos
>
0
)
{
if
(
r
->
pos
==
sdslen
(
r
->
buf
)
)
{
if
(
r
->
pos
==
r
->
len
)
{
/* sdsrange has a quirck on this edge case. */
sdsfree
(
r
->
buf
);
r
->
buf
=
sdsempty
();
}
else
{
r
->
buf
=
sdsrange
(
r
->
buf
,
r
->
pos
,
sdslen
(
r
->
buf
)
);
r
->
buf
=
sdsrange
(
r
->
buf
,
r
->
pos
,
r
->
len
);
}
r
->
pos
=
0
;
r
->
len
=
sdslen
(
r
->
buf
);
}
/* Emit a reply when there is one. */
...
...
@@ -481,7 +557,7 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
r
->
reply
=
NULL
;
/* Destroy the buffer when it is empty and is quite large. */
if
(
sdslen
(
r
->
buf
)
==
0
&&
sdsavail
(
r
->
buf
)
>
16
*
1024
)
{
if
(
r
->
len
==
0
&&
sdsavail
(
r
->
buf
)
>
16
*
1024
)
{
sdsfree
(
r
->
buf
);
r
->
buf
=
sdsempty
();
r
->
pos
=
0
;
...
...
@@ -525,6 +601,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
char
*
cmd
=
NULL
;
/* final command */
int
pos
;
/* position in final command */
sds
current
;
/* current argument */
int
interpolated
=
0
;
/* did we do interpolation on an argument? */
char
**
argv
=
NULL
;
int
argc
=
0
,
j
;
int
totlen
=
0
;
...
...
@@ -541,6 +618,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if
(
sdslen
(
current
)
!=
0
)
{
addArgument
(
current
,
&
argv
,
&
argc
,
&
totlen
);
current
=
sdsempty
();
interpolated
=
0
;
}
}
else
{
current
=
sdscatlen
(
current
,
c
,
1
);
...
...
@@ -549,16 +627,74 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
switch
(
c
[
1
])
{
case
's'
:
arg
=
va_arg
(
ap
,
char
*
);
current
=
sdscat
(
current
,
arg
);
size
=
strlen
(
arg
);
if
(
size
>
0
)
current
=
sdscatlen
(
current
,
arg
,
size
);
interpolated
=
1
;
break
;
case
'b'
:
arg
=
va_arg
(
ap
,
char
*
);
size
=
va_arg
(
ap
,
size_t
);
if
(
size
>
0
)
current
=
sdscatlen
(
current
,
arg
,
size
);
interpolated
=
1
;
break
;
case
'%'
:
c
md
=
sdscat
(
c
md
,
"%"
);
c
urrent
=
sdscat
(
c
urrent
,
"%"
);
break
;
default:
/* Try to detect printf format */
{
char
_format
[
16
];
const
char
*
_p
=
c
+
1
;
size_t
_l
=
0
;
va_list
_cpy
;
/* Flags */
if
(
*
_p
!=
'\0'
&&
*
_p
==
'#'
)
_p
++
;
if
(
*
_p
!=
'\0'
&&
*
_p
==
'0'
)
_p
++
;
if
(
*
_p
!=
'\0'
&&
*
_p
==
'-'
)
_p
++
;
if
(
*
_p
!=
'\0'
&&
*
_p
==
' '
)
_p
++
;
if
(
*
_p
!=
'\0'
&&
*
_p
==
'+'
)
_p
++
;
/* Field width */
while
(
*
_p
!=
'\0'
&&
isdigit
(
*
_p
))
_p
++
;
/* Precision */
if
(
*
_p
==
'.'
)
{
_p
++
;
while
(
*
_p
!=
'\0'
&&
isdigit
(
*
_p
))
_p
++
;
}
/* Modifiers */
if
(
*
_p
!=
'\0'
)
{
if
(
*
_p
==
'h'
||
*
_p
==
'l'
)
{
/* Allow a single repetition for these modifiers */
if
(
_p
[
0
]
==
_p
[
1
])
_p
++
;
_p
++
;
}
}
/* Conversion specifier */
if
(
*
_p
!=
'\0'
&&
strchr
(
"diouxXeEfFgGaA"
,
*
_p
)
!=
NULL
)
{
_l
=
(
_p
+
1
)
-
c
;
if
(
_l
<
sizeof
(
_format
)
-
2
)
{
memcpy
(
_format
,
c
,
_l
);
_format
[
_l
]
=
'\0'
;
va_copy
(
_cpy
,
ap
);
current
=
sdscatvprintf
(
current
,
_format
,
_cpy
);
interpolated
=
1
;
va_end
(
_cpy
);
/* Update current position (note: outer blocks
* increment c twice so compensate here) */
c
=
_p
-
1
;
}
}
/* Consume and discard vararg */
va_arg
(
ap
,
void
);
}
}
c
++
;
}
...
...
@@ -566,7 +702,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
}
/* Add the last argument if needed */
if
(
sdslen
(
current
)
!=
0
)
{
if
(
interpolated
||
sdslen
(
current
)
!=
0
)
{
addArgument
(
current
,
&
argv
,
&
argc
,
&
totlen
);
}
else
{
sdsfree
(
current
);
...
...
@@ -664,7 +800,6 @@ void __redisSetError(redisContext *c, int type, const sds errstr) {
static
redisContext
*
redisContextInit
()
{
redisContext
*
c
=
calloc
(
sizeof
(
redisContext
),
1
);
c
->
fd
=
-
1
;
/* quick fix for a bug that should be addressed differently */
c
->
err
=
0
;
c
->
errstr
=
NULL
;
c
->
obuf
=
sdsempty
();
...
...
@@ -692,7 +827,6 @@ void redisFree(redisContext *c) {
redisContext
*
redisConnect
(
const
char
*
ip
,
int
port
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
|=
REDIS_BLOCK
;
c
->
flags
|=
REDIS_CONNECTED
;
redisContextConnectTcp
(
c
,
ip
,
port
);
return
c
;
}
...
...
@@ -700,7 +834,6 @@ redisContext *redisConnect(const char *ip, int port) {
redisContext
*
redisConnectNonBlock
(
const
char
*
ip
,
int
port
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
&=
~
REDIS_BLOCK
;
c
->
flags
|=
REDIS_CONNECTED
;
redisContextConnectTcp
(
c
,
ip
,
port
);
return
c
;
}
...
...
@@ -708,7 +841,6 @@ redisContext *redisConnectNonBlock(const char *ip, int port) {
redisContext
*
redisConnectUnix
(
const
char
*
path
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
|=
REDIS_BLOCK
;
c
->
flags
|=
REDIS_CONNECTED
;
redisContextConnectUnix
(
c
,
path
);
return
c
;
}
...
...
@@ -716,7 +848,6 @@ redisContext *redisConnectUnix(const char *path) {
redisContext
*
redisConnectUnixNonBlock
(
const
char
*
path
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
&=
~
REDIS_BLOCK
;
c
->
flags
|=
REDIS_CONNECTED
;
redisContextConnectUnix
(
c
,
path
);
return
c
;
}
...
...
deps/hiredis/hiredis.h
View file @
021321e0
/*
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
...
...
@@ -34,7 +36,7 @@
#define HIREDIS_MAJOR 0
#define HIREDIS_MINOR 9
#define HIREDIS_PATCH
0
#define HIREDIS_PATCH
2
#define REDIS_ERR -1
#define REDIS_OK 0
...
...
@@ -62,12 +64,16 @@
* should be terminated once all replies have been read. */
#define REDIS_DISCONNECTING 0x4
#define REDIS_REPLY_ERROR 0
#define REDIS_REPLY_STRING 1
#define REDIS_REPLY_ARRAY 2
#define REDIS_REPLY_INTEGER 3
#define REDIS_REPLY_NIL 4
#define REDIS_REPLY_STATUS 5
#define REDIS_REPLY_ERROR 6
#ifdef __cplusplus
extern
"C"
{
#endif
/* This is the reply object returned by redisCommand() */
typedef
struct
redisReply
{
...
...
@@ -82,8 +88,10 @@ typedef struct redisReply {
typedef
struct
redisReadTask
{
int
type
;
int
elements
;
/* number of elements in multibulk container */
void
*
parent
;
/* optional pointer to parent object */
int
idx
;
/* index in parent (array) object */
void
*
obj
;
/* holds user-generated value for a read task */
struct
redisReadTask
*
parent
;
/* parent task */
void
*
privdata
;
/* user-settable arbitrary field */
}
redisReadTask
;
typedef
struct
redisReplyObjectFunctions
{
...
...
@@ -112,6 +120,7 @@ typedef struct redisContext {
void
freeReplyObject
(
void
*
reply
);
void
*
redisReplyReaderCreate
();
int
redisReplyReaderSetReplyObjectFunctions
(
void
*
reader
,
redisReplyObjectFunctions
*
fn
);
int
redisReplyReaderSetPrivdata
(
void
*
reader
,
void
*
privdata
);
void
*
redisReplyReaderGetObject
(
void
*
reader
);
char
*
redisReplyReaderGetError
(
void
*
reader
);
void
redisReplyReaderFree
(
void
*
ptr
);
...
...
@@ -154,4 +163,8 @@ void *redisvCommand(redisContext *c, const char *format, va_list ap);
void
*
redisCommand
(
redisContext
*
c
,
const
char
*
format
,
...);
void
*
redisCommandArgv
(
redisContext
*
c
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
#ifdef __cplusplus
}
#endif
#endif
deps/hiredis/net.c
View file @
021321e0
/* Extracted from anet.c to work properly with Hiredis error reporting.
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
*
All
right
s reserved.
*
Copy
right
(c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
...
...
@@ -43,7 +44,7 @@
#include <stdarg.h>
#include <stdio.h>
#include "
hiredis
.h"
#include "
net
.h"
#include "sds.h"
/* Forward declaration */
...
...
@@ -114,7 +115,7 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port) {
he
=
gethostbyname
(
addr
);
if
(
he
==
NULL
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
sdscatprintf
(
sdsempty
(),
"
c
an't resolve: %s"
,
addr
));
sdscatprintf
(
sdsempty
(),
"
C
an't resolve: %s"
,
addr
));
close
(
s
);
return
REDIS_ERR
;
}
...
...
@@ -137,6 +138,7 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port) {
}
c
->
fd
=
s
;
c
->
flags
|=
REDIS_CONNECTED
;
return
REDIS_OK
;
}
...
...
@@ -163,5 +165,6 @@ int redisContextConnectUnix(redisContext *c, const char *path) {
}
c
->
fd
=
s
;
c
->
flags
|=
REDIS_CONNECTED
;
return
REDIS_OK
;
}
deps/hiredis/net.h
View file @
021321e0
...
...
@@ -31,6 +31,12 @@
#ifndef __NET_H
#define __NET_H
#include "hiredis.h"
#if defined(__sun)
#define AF_LOCAL AF_UNIX
#endif
int
redisContextConnectTcp
(
redisContext
*
c
,
const
char
*
addr
,
int
port
);
int
redisContextConnectUnix
(
redisContext
*
c
,
const
char
*
path
);
...
...
deps/hiredis/test.c
View file @
021321e0
...
...
@@ -47,17 +47,59 @@ static void test_format_commands() {
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
));
free
(
cmd
);
test
(
"Format command with %%s and an empty string: "
);
len
=
redisFormatCommand
(
&
cmd
,
"SET %s %s"
,
"foo"
,
""
);
test_cond
(
strncmp
(
cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$3
\r\n
foo
\r\n
$0
\r\n\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
)
+
4
+
(
0
+
2
));
free
(
cmd
);
test
(
"Format command with %%b string interpolation: "
);
len
=
redisFormatCommand
(
&
cmd
,
"SET %b %b"
,
"foo"
,
3
,
"b
\0
r"
,
3
);
test_cond
(
strncmp
(
cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$3
\r\n
foo
\r\n
$3
\r\n
b
\0
r
\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
);
test_cond
(
strncmp
(
cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$3
\r\n
foo
\r\n
$0
\r\n\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
)
+
4
+
(
0
+
2
));
free
(
cmd
);
test
(
"Format command with literal %%: "
);
len
=
redisFormatCommand
(
&
cmd
,
"SET %% %%"
);
test_cond
(
strncmp
(
cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$1
\r\n
%
\r\n
$1
\r\n
%
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
1
+
2
)
+
4
+
(
1
+
2
));
free
(
cmd
);
test
(
"Format command with printf-delegation (long long): "
);
len
=
redisFormatCommand
(
&
cmd
,
"key:%08lld"
,
1234ll
);
test_cond
(
strncmp
(
cmd
,
"*1
\r\n
$12
\r\n
key:00001234
\r\n
"
,
len
)
==
0
&&
len
==
4
+
5
+
(
12
+
2
));
free
(
cmd
);
test
(
"Format command with printf-delegation (float): "
);
len
=
redisFormatCommand
(
&
cmd
,
"v:%06.1f"
,
12
.
34
f
);
test_cond
(
strncmp
(
cmd
,
"*1
\r\n
$8
\r\n
v:0012.3
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
8
+
2
));
free
(
cmd
);
test
(
"Format command with printf-delegation and extra interpolation: "
);
len
=
redisFormatCommand
(
&
cmd
,
"key:%d %b"
,
1234
,
"foo"
,
3
);
test_cond
(
strncmp
(
cmd
,
"*2
\r\n
$8
\r\n
key:1234
\r\n
$3
\r\n
foo
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
8
+
2
)
+
4
+
(
3
+
2
));
free
(
cmd
);
test
(
"Format command with wrong printf format and extra interpolation: "
);
len
=
redisFormatCommand
(
&
cmd
,
"key:%08p %b"
,
1234
,
"foo"
,
3
);
test_cond
(
strncmp
(
cmd
,
"*2
\r\n
$6
\r\n
key:8p
\r\n
$3
\r\n
foo
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
6
+
2
)
+
4
+
(
3
+
2
));
free
(
cmd
);
const
char
*
argv
[
3
];
argv
[
0
]
=
"SET"
;
argv
[
1
]
=
"foo"
;
argv
[
1
]
=
"foo
\0
xxx
"
;
argv
[
2
]
=
"bar"
;
size_t
lens
[
3
]
=
{
3
,
3
,
3
};
size_t
lens
[
3
]
=
{
3
,
7
,
3
};
int
argc
=
3
;
test
(
"Format command by passing argc/argv without lengths: "
);
...
...
@@ -68,38 +110,29 @@ static void test_format_commands() {
test
(
"Format command by passing argc/argv with lengths: "
);
len
=
redisFormatCommandArgv
(
&
cmd
,
argc
,
argv
,
lens
);
test_cond
(
strncmp
(
cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$
3
\r\n
foo
\r\n
$3
\r\n
bar
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
));
test_cond
(
strncmp
(
cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$
7
\r\n
foo
\
0
xxx
\
r\n
$3
\r\n
bar
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
7
+
2
)
+
4
+
(
3
+
2
));
free
(
cmd
);
}
static
void
test_blocking_connection
()
{
redisContext
*
c
;
redisReply
*
reply
;
int
major
,
minor
;
__connect
(
&
c
);
test
(
"Returns I/O error when the connection is lost: "
);
reply
=
redisCommand
(
c
,
"QUIT"
);
test_cond
(
strcasecmp
(
reply
->
str
,
"OK"
)
==
0
&&
redisCommand
(
c
,
"PING"
)
==
NULL
);
/* Two conditions may happen, depending on the type of connection.
* When connected via TCP, the socket will not yet be aware of the closed
* connection and the write(2) call will succeed, but the read(2) will
* result in an EOF. When connected via Unix sockets, the socket will be
* immediately aware that it was closed and fail on the write(2) call. */
if
(
use_unix
)
{
fprintf
(
stderr
,
"Error: %s
\n
"
,
c
->
errstr
);
assert
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Broken pipe"
)
==
0
);
}
else
{
fprintf
(
stderr
,
"Error: %s
\n
"
,
c
->
errstr
);
assert
(
c
->
err
==
REDIS_ERR_EOF
&&
strcmp
(
c
->
errstr
,
"Server closed the connection"
)
==
0
);
}
freeReplyObject
(
reply
);
test
(
"Returns error when host cannot be resolved: "
);
c
=
redisConnect
((
char
*
)
"idontexist.local"
,
6379
);
test_cond
(
c
->
err
==
REDIS_ERR_OTHER
&&
strcmp
(
c
->
errstr
,
"Can't resolve: idontexist.local"
)
==
0
);
redisFree
(
c
);
test
(
"Returns error when the port is not open: "
);
c
=
redisConnect
((
char
*
)
"localhost"
,
56380
);
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Connection refused"
)
==
0
);
redisFree
(
c
);
__connect
(
&
c
);
/* reconnect */
__connect
(
&
c
);
test
(
"Is able to deliver commands: "
);
reply
=
redisCommand
(
c
,
"PING"
);
test_cond
(
reply
->
type
==
REDIS_REPLY_STATUS
&&
...
...
@@ -112,12 +145,9 @@ static void test_blocking_connection() {
/* Make sure the DB is emtpy */
reply
=
redisCommand
(
c
,
"DBSIZE"
);
if
(
reply
->
type
!=
REDIS_REPLY_INTEGER
||
reply
->
integer
!=
0
)
{
printf
(
"Sorry DB 9 is not empty, test can not continue
\n
"
);
if
(
reply
->
type
!=
REDIS_REPLY_INTEGER
||
reply
->
integer
!=
0
)
{
printf
(
"Database #9 is not empty, test can not continue
\n
"
);
exit
(
1
);
}
else
{
printf
(
"DB 9 is empty... test can continue
\n
"
);
}
freeReplyObject
(
reply
);
...
...
@@ -183,6 +213,43 @@ static void test_blocking_connection() {
reply
->
element
[
1
]
->
type
==
REDIS_REPLY_STATUS
&&
strcasecmp
(
reply
->
element
[
1
]
->
str
,
"pong"
)
==
0
);
freeReplyObject
(
reply
);
{
/* Find out Redis version to determine the path for the next test */
const
char
*
field
=
"redis_version:"
;
char
*
p
,
*
eptr
;
reply
=
redisCommand
(
c
,
"INFO"
);
p
=
strstr
(
reply
->
str
,
field
);
major
=
strtol
(
p
+
strlen
(
field
),
&
eptr
,
10
);
p
=
eptr
+
1
;
/* char next to the first "." */
minor
=
strtol
(
p
,
&
eptr
,
10
);
freeReplyObject
(
reply
);
}
test
(
"Returns I/O error when the connection is lost: "
);
reply
=
redisCommand
(
c
,
"QUIT"
);
if
(
major
>=
2
&&
minor
>
0
)
{
/* > 2.0 returns OK on QUIT and read() should be issued once more
* to know the descriptor is at EOF. */
test_cond
(
strcasecmp
(
reply
->
str
,
"OK"
)
==
0
&&
redisGetReply
(
c
,(
void
**
)
&
reply
)
==
REDIS_ERR
);
freeReplyObject
(
reply
);
}
else
{
test_cond
(
reply
==
NULL
);
}
/* On 2.0, QUIT will cause the connection to be closed immediately and
* the read(2) for the reply on QUIT will set the error to EOF.
* On >2.0, QUIT will return with OK and another read(2) needed to be
* issued to find out the socket was closed by the server. In both
* conditions, the error will be set to EOF. */
assert
(
c
->
err
==
REDIS_ERR_EOF
&&
strcmp
(
c
->
errstr
,
"Server closed the connection"
)
==
0
);
/* Clean up context and reconnect again */
redisFree
(
c
);
__connect
(
&
c
);
}
static
void
test_reply_reader
()
{
...
...
@@ -197,7 +264,7 @@ static void test_reply_reader() {
ret
=
redisReplyReaderGetReply
(
reader
,
NULL
);
err
=
redisReplyReaderGetError
(
reader
);
test_cond
(
ret
==
REDIS_ERR
&&
strcasecmp
(
err
,
"
p
rotocol error, got
\"
@
\"
as reply type byte"
)
==
0
);
strcasecmp
(
err
,
"
P
rotocol error, got
\"
@
\"
as reply type byte"
)
==
0
);
redisReplyReaderFree
(
reader
);
/* when the reply already contains multiple items, they must be free'd
...
...
@@ -210,7 +277,18 @@ static void test_reply_reader() {
ret
=
redisReplyReaderGetReply
(
reader
,
NULL
);
err
=
redisReplyReaderGetError
(
reader
);
test_cond
(
ret
==
REDIS_ERR
&&
strcasecmp
(
err
,
"protocol error, got
\"
@
\"
as reply type byte"
)
==
0
);
strcasecmp
(
err
,
"Protocol error, got
\"
@
\"
as reply type byte"
)
==
0
);
redisReplyReaderFree
(
reader
);
test
(
"Set error on nested multi bulks with depth > 1: "
);
reader
=
redisReplyReaderCreate
();
redisReplyReaderFeed
(
reader
,(
char
*
)
"*1
\r\n
"
,
4
);
redisReplyReaderFeed
(
reader
,(
char
*
)
"*1
\r\n
"
,
4
);
redisReplyReaderFeed
(
reader
,(
char
*
)
"*1
\r\n
"
,
4
);
ret
=
redisReplyReaderGetReply
(
reader
,
NULL
);
err
=
redisReplyReaderGetError
(
reader
);
test_cond
(
ret
==
REDIS_ERR
&&
strncasecmp
(
err
,
"No support for"
,
14
)
==
0
);
redisReplyReaderFree
(
reader
);
test
(
"Works with NULL functions for reply: "
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment