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
2eaf2360
Commit
2eaf2360
authored
May 30, 2023
by
Yossi Gottlieb
Browse files
Merge commit '
fad6c713
' into hiredis-refresh
parents
c2f1815b
fad6c713
Changes
41
Hide whitespace changes
Inline
Side-by-side
deps/hiredis/examples/example-redismoduleapi.c
0 → 100644
View file @
2eaf2360
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <hiredis.h>
#include <async.h>
#include <adapters/redismoduleapi.h>
void
debugCallback
(
redisAsyncContext
*
c
,
void
*
r
,
void
*
privdata
)
{
(
void
)
privdata
;
//unused
redisReply
*
reply
=
r
;
if
(
reply
==
NULL
)
{
/* The DEBUG SLEEP command will almost always fail, because we have set a 1 second timeout */
printf
(
"`DEBUG SLEEP` error: %s
\n
"
,
c
->
errstr
?
c
->
errstr
:
"unknown error"
);
return
;
}
/* Disconnect after receiving the reply of DEBUG SLEEP (which will not)*/
redisAsyncDisconnect
(
c
);
}
void
getCallback
(
redisAsyncContext
*
c
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
if
(
reply
==
NULL
)
{
if
(
c
->
errstr
)
{
printf
(
"errstr: %s
\n
"
,
c
->
errstr
);
}
return
;
}
printf
(
"argv[%s]: %s
\n
"
,
(
char
*
)
privdata
,
reply
->
str
);
/* start another request that demonstrate timeout */
redisAsyncCommand
(
c
,
debugCallback
,
NULL
,
"DEBUG SLEEP %f"
,
1
.
5
);
}
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
"
);
}
/*
* This example requires Redis 7.0 or above.
*
* 1- Compile this file as a shared library. Directory of "redismodule.h" must
* be in the include path.
* gcc -fPIC -shared -I../../redis/src/ -I.. example-redismoduleapi.c -o example-redismoduleapi.so
*
* 2- Load module:
* redis-server --loadmodule ./example-redismoduleapi.so value
*/
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
int
ret
=
RedisModule_Init
(
ctx
,
"example-redismoduleapi"
,
1
,
REDISMODULE_APIVER_1
);
if
(
ret
!=
REDISMODULE_OK
)
{
printf
(
"error module init
\n
"
);
return
REDISMODULE_ERR
;
}
if
(
redisModuleCompatibilityCheck
()
!=
REDIS_OK
)
{
printf
(
"Redis 7.0 or above is required!
\n
"
);
return
REDISMODULE_ERR
;
}
redisAsyncContext
*
c
=
redisAsyncConnect
(
"127.0.0.1"
,
6379
);
if
(
c
->
err
)
{
/* Let *c leak for now... */
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
1
;
}
size_t
len
;
const
char
*
val
=
RedisModule_StringPtrLen
(
argv
[
argc
-
1
],
&
len
);
RedisModuleCtx
*
module_ctx
=
RedisModule_GetDetachedThreadSafeContext
(
ctx
);
redisModuleAttach
(
c
,
module_ctx
);
redisAsyncSetConnectCallback
(
c
,
connectCallback
);
redisAsyncSetDisconnectCallback
(
c
,
disconnectCallback
);
redisAsyncSetTimeout
(
c
,
(
struct
timeval
){
.
tv_sec
=
1
,
.
tv_usec
=
0
});
/*
In this demo, we first `set key`, then `get key` to demonstrate the basic usage of the adapter.
Then in `getCallback`, we start a `debug sleep` command to create 1.5 second long request.
Because we have set a 1 second timeout to the connection, the command will always fail with a
timeout error, which is shown in the `debugCallback`.
*/
redisAsyncCommand
(
c
,
NULL
,
NULL
,
"SET key %b"
,
val
,
len
);
redisAsyncCommand
(
c
,
getCallback
,
(
char
*
)
"end-1"
,
"GET key"
);
return
0
;
}
deps/hiredis/examples/example-ssl.c
View file @
2eaf2360
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
unsigned
int
j
;
unsigned
int
j
;
redisSSLContext
*
ssl
;
redisSSLContext
*
ssl
;
redisSSLContextError
ssl_error
;
redisSSLContextError
ssl_error
=
REDIS_SSL_CTX_NONE
;
redisContext
*
c
;
redisContext
*
c
;
redisReply
*
reply
;
redisReply
*
reply
;
if
(
argc
<
4
)
{
if
(
argc
<
4
)
{
...
@@ -27,9 +27,8 @@ int main(int argc, char **argv) {
...
@@ -27,9 +27,8 @@ int main(int argc, char **argv) {
redisInitOpenSSL
();
redisInitOpenSSL
();
ssl
=
redisCreateSSLContext
(
ca
,
NULL
,
cert
,
key
,
NULL
,
&
ssl_error
);
ssl
=
redisCreateSSLContext
(
ca
,
NULL
,
cert
,
key
,
NULL
,
&
ssl_error
);
if
(
!
ssl
)
{
if
(
!
ssl
||
ssl_error
!=
REDIS_SSL_CTX_NONE
)
{
printf
(
"SSL Context error: %s
\n
"
,
printf
(
"SSL Context error: %s
\n
"
,
redisSSLContextGetError
(
ssl_error
));
redisSSLContextGetError
(
ssl_error
));
exit
(
1
);
exit
(
1
);
}
}
...
...
deps/hiredis/examples/example.c
View file @
2eaf2360
...
@@ -7,6 +7,54 @@
...
@@ -7,6 +7,54 @@
#include <winsock2.h>
/* For struct timeval */
#include <winsock2.h>
/* For struct timeval */
#endif
#endif
static
void
example_argv_command
(
redisContext
*
c
,
size_t
n
)
{
char
**
argv
,
tmp
[
42
];
size_t
*
argvlen
;
redisReply
*
reply
;
/* We're allocating two additional elements for command and key */
argv
=
malloc
(
sizeof
(
*
argv
)
*
(
2
+
n
));
argvlen
=
malloc
(
sizeof
(
*
argvlen
)
*
(
2
+
n
));
/* First the command */
argv
[
0
]
=
(
char
*
)
"RPUSH"
;
argvlen
[
0
]
=
sizeof
(
"RPUSH"
)
-
1
;
/* Now our key */
argv
[
1
]
=
(
char
*
)
"argvlist"
;
argvlen
[
1
]
=
sizeof
(
"argvlist"
)
-
1
;
/* Now add the entries we wish to add to the list */
for
(
size_t
i
=
2
;
i
<
(
n
+
2
);
i
++
)
{
argvlen
[
i
]
=
snprintf
(
tmp
,
sizeof
(
tmp
),
"argv-element-%zu"
,
i
-
2
);
argv
[
i
]
=
strdup
(
tmp
);
}
/* Execute the command using redisCommandArgv. We're sending the arguments with
* two explicit arrays. One for each argument's string, and the other for its
* length. */
reply
=
redisCommandArgv
(
c
,
n
+
2
,
(
const
char
**
)
argv
,
(
const
size_t
*
)
argvlen
);
if
(
reply
==
NULL
||
c
->
err
)
{
fprintf
(
stderr
,
"Error: Couldn't execute redisCommandArgv
\n
"
);
exit
(
1
);
}
if
(
reply
->
type
==
REDIS_REPLY_INTEGER
)
{
printf
(
"%s reply: %lld
\n
"
,
argv
[
0
],
reply
->
integer
);
}
freeReplyObject
(
reply
);
/* Clean up */
for
(
size_t
i
=
2
;
i
<
(
n
+
2
);
i
++
)
{
free
(
argv
[
i
]);
}
free
(
argv
);
free
(
argvlen
);
}
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
unsigned
int
j
,
isunix
=
0
;
unsigned
int
j
,
isunix
=
0
;
redisContext
*
c
;
redisContext
*
c
;
...
@@ -87,6 +135,9 @@ int main(int argc, char **argv) {
...
@@ -87,6 +135,9 @@ int main(int argc, char **argv) {
}
}
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
/* See function for an example of redisCommandArgv */
example_argv_command
(
c
,
10
);
/* Disconnects and frees the context */
/* Disconnects and frees the context */
redisFree
(
c
);
redisFree
(
c
);
...
...
deps/hiredis/fuzzing/format_command_fuzzer.c
View file @
2eaf2360
...
@@ -48,10 +48,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
...
@@ -48,10 +48,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memcpy
(
new_str
,
data
,
size
);
memcpy
(
new_str
,
data
,
size
);
new_str
[
size
]
=
'\0'
;
new_str
[
size
]
=
'\0'
;
redisFormatCommand
(
&
cmd
,
new_str
);
if
(
redisFormatCommand
(
&
cmd
,
new_str
)
!=
-
1
)
if
(
cmd
!=
NULL
)
hi_free
(
cmd
);
hi_free
(
cmd
);
free
(
new_str
);
free
(
new_str
);
return
0
;
return
0
;
}
}
deps/hiredis/hiredis-config.cmake.in
View file @
2eaf2360
...
@@ -2,11 +2,11 @@
...
@@ -2,11 +2,11 @@
set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
IF (NOT TARGET hiredis::hiredis)
IF (NOT TARGET hiredis::
@
hiredis
_export_name@
)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake)
ENDIF()
ENDIF()
SET(hiredis_LIBRARIES hiredis::hiredis)
SET(hiredis_LIBRARIES hiredis::
@
hiredis
_export_name@
)
SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR})
SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR})
check_required_components(hiredis)
check_required_components(hiredis)
...
...
deps/hiredis/hiredis.c
View file @
2eaf2360
...
@@ -48,6 +48,7 @@ extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeva
...
@@ -48,6 +48,7 @@ extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeva
extern
int
redisContextUpdateCommandTimeout
(
redisContext
*
c
,
const
struct
timeval
*
timeout
);
extern
int
redisContextUpdateCommandTimeout
(
redisContext
*
c
,
const
struct
timeval
*
timeout
);
static
redisContextFuncs
redisContextDefaultFuncs
=
{
static
redisContextFuncs
redisContextDefaultFuncs
=
{
.
close
=
redisNetClose
,
.
free_privctx
=
NULL
,
.
free_privctx
=
NULL
,
.
async_read
=
redisAsyncRead
,
.
async_read
=
redisAsyncRead
,
.
async_write
=
redisAsyncWrite
,
.
async_write
=
redisAsyncWrite
,
...
@@ -221,6 +222,9 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
...
@@ -221,6 +222,9 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
static
void
*
createDoubleObject
(
const
redisReadTask
*
task
,
double
value
,
char
*
str
,
size_t
len
)
{
static
void
*
createDoubleObject
(
const
redisReadTask
*
task
,
double
value
,
char
*
str
,
size_t
len
)
{
redisReply
*
r
,
*
parent
;
redisReply
*
r
,
*
parent
;
if
(
len
==
SIZE_MAX
)
// Prevents hi_malloc(0) if len equals to SIZE_MAX
return
NULL
;
r
=
createReplyObject
(
REDIS_REPLY_DOUBLE
);
r
=
createReplyObject
(
REDIS_REPLY_DOUBLE
);
if
(
r
==
NULL
)
if
(
r
==
NULL
)
return
NULL
;
return
NULL
;
...
@@ -399,6 +403,11 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -399,6 +403,11 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
/* Copy va_list before consuming with va_arg */
/* Copy va_list before consuming with va_arg */
va_copy
(
_cpy
,
ap
);
va_copy
(
_cpy
,
ap
);
/* Make sure we have more characters otherwise strchr() accepts
* '\0' as an integer specifier. This is checked after above
* va_copy() to avoid UB in fmt_invalid's call to va_end(). */
if
(
*
_p
==
'\0'
)
goto
fmt_invalid
;
/* Integer conversion (without modifiers) */
/* Integer conversion (without modifiers) */
if
(
strchr
(
intfmts
,
*
_p
)
!=
NULL
)
{
if
(
strchr
(
intfmts
,
*
_p
)
!=
NULL
)
{
va_arg
(
ap
,
int
);
va_arg
(
ap
,
int
);
...
@@ -477,6 +486,8 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -477,6 +486,8 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
touched
=
1
;
touched
=
1
;
c
++
;
c
++
;
if
(
*
c
==
'\0'
)
break
;
}
}
c
++
;
c
++
;
}
}
...
@@ -719,7 +730,10 @@ static redisContext *redisContextInit(void) {
...
@@ -719,7 +730,10 @@ static redisContext *redisContextInit(void) {
void
redisFree
(
redisContext
*
c
)
{
void
redisFree
(
redisContext
*
c
)
{
if
(
c
==
NULL
)
if
(
c
==
NULL
)
return
;
return
;
redisNetClose
(
c
);
if
(
c
->
funcs
&&
c
->
funcs
->
close
)
{
c
->
funcs
->
close
(
c
);
}
hi_sdsfree
(
c
->
obuf
);
hi_sdsfree
(
c
->
obuf
);
redisReaderFree
(
c
->
reader
);
redisReaderFree
(
c
->
reader
);
...
@@ -733,7 +747,7 @@ void redisFree(redisContext *c) {
...
@@ -733,7 +747,7 @@ void redisFree(redisContext *c) {
if
(
c
->
privdata
&&
c
->
free_privdata
)
if
(
c
->
privdata
&&
c
->
free_privdata
)
c
->
free_privdata
(
c
->
privdata
);
c
->
free_privdata
(
c
->
privdata
);
if
(
c
->
funcs
->
free_privctx
)
if
(
c
->
funcs
&&
c
->
funcs
->
free_privctx
)
c
->
funcs
->
free_privctx
(
c
->
privctx
);
c
->
funcs
->
free_privctx
(
c
->
privctx
);
memset
(
c
,
0xff
,
sizeof
(
*
c
));
memset
(
c
,
0xff
,
sizeof
(
*
c
));
...
@@ -756,7 +770,9 @@ int redisReconnect(redisContext *c) {
...
@@ -756,7 +770,9 @@ int redisReconnect(redisContext *c) {
c
->
privctx
=
NULL
;
c
->
privctx
=
NULL
;
}
}
redisNetClose
(
c
);
if
(
c
->
funcs
&&
c
->
funcs
->
close
)
{
c
->
funcs
->
close
(
c
);
}
hi_sdsfree
(
c
->
obuf
);
hi_sdsfree
(
c
->
obuf
);
redisReaderFree
(
c
->
reader
);
redisReaderFree
(
c
->
reader
);
...
@@ -806,6 +822,12 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
...
@@ -806,6 +822,12 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
if
(
options
->
options
&
REDIS_OPT_NOAUTOFREEREPLIES
)
{
if
(
options
->
options
&
REDIS_OPT_NOAUTOFREEREPLIES
)
{
c
->
flags
|=
REDIS_NO_AUTO_FREE_REPLIES
;
c
->
flags
|=
REDIS_NO_AUTO_FREE_REPLIES
;
}
}
if
(
options
->
options
&
REDIS_OPT_PREFER_IPV4
)
{
c
->
flags
|=
REDIS_PREFER_IPV4
;
}
if
(
options
->
options
&
REDIS_OPT_PREFER_IPV6
)
{
c
->
flags
|=
REDIS_PREFER_IPV6
;
}
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject
* as a default unless specifically flagged that we don't want one. */
* as a default unless specifically flagged that we don't want one. */
...
@@ -838,7 +860,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
...
@@ -838,7 +860,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
return
NULL
;
return
NULL
;
}
}
if
(
options
->
command_timeout
!=
NULL
&&
(
c
->
flags
&
REDIS_BLOCK
)
&&
c
->
fd
!=
REDIS_INVALID_FD
)
{
if
(
c
->
err
==
0
&&
c
->
fd
!=
REDIS_INVALID_FD
&&
options
->
command_timeout
!=
NULL
&&
(
c
->
flags
&
REDIS_BLOCK
))
{
redisContextSetTimeout
(
c
,
*
options
->
command_timeout
);
redisContextSetTimeout
(
c
,
*
options
->
command_timeout
);
}
}
...
@@ -920,11 +944,18 @@ int redisSetTimeout(redisContext *c, const struct timeval tv) {
...
@@ -920,11 +944,18 @@ int redisSetTimeout(redisContext *c, const struct timeval tv) {
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
int
redisEnableKeepAliveWithInterval
(
redisContext
*
c
,
int
interval
)
{
return
redisKeepAlive
(
c
,
interval
);
}
/* Enable connection KeepAlive. */
/* Enable connection KeepAlive. */
int
redisEnableKeepAlive
(
redisContext
*
c
)
{
int
redisEnableKeepAlive
(
redisContext
*
c
)
{
if
(
redisKeepAlive
(
c
,
REDIS_KEEPALIVE_INTERVAL
)
!=
REDIS_OK
)
return
redisKeepAlive
(
c
,
REDIS_KEEPALIVE_INTERVAL
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
/* Set the socket option TCP_USER_TIMEOUT. */
int
redisSetTcpUserTimeout
(
redisContext
*
c
,
unsigned
int
timeout
)
{
return
redisContextSetTcpUserTimeout
(
c
,
timeout
);
}
}
/* Set a user provided RESP3 PUSH handler and return any old one set. */
/* Set a user provided RESP3 PUSH handler and return any old one set. */
...
@@ -964,8 +995,8 @@ int redisBufferRead(redisContext *c) {
...
@@ -964,8 +995,8 @@ int redisBufferRead(redisContext *c) {
* successfully written to the socket. When the buffer is empty after the
* successfully written to the socket. When the buffer is empty after the
* write operation, "done" is set to 1 (if given).
* write operation, "done" is set to 1 (if given).
*
*
* Returns REDIS_ERR if an error occurred
try
in
g
t
o writ
e
a
nd
sets
* Returns REDIS_ERR if an
unrecoverable
error occurred in t
h
e
u
nd
erlying
* c->
errstr to hold the approp
ri
a
te
error string
.
* c->
funcs->w
rite
function
.
*/
*/
int
redisBufferWrite
(
redisContext
*
c
,
int
*
done
)
{
int
redisBufferWrite
(
redisContext
*
c
,
int
*
done
)
{
...
...
deps/hiredis/hiredis.h
View file @
2eaf2360
...
@@ -46,9 +46,9 @@ typedef long long ssize_t;
...
@@ -46,9 +46,9 @@ typedef long long ssize_t;
#include "alloc.h"
/* for allocation wrappers */
#include "alloc.h"
/* for allocation wrappers */
#define HIREDIS_MAJOR 1
#define HIREDIS_MAJOR 1
#define HIREDIS_MINOR
0
#define HIREDIS_MINOR
1
#define HIREDIS_PATCH
3
#define HIREDIS_PATCH
1
#define HIREDIS_SONAME 1.
0.3
-dev
#define HIREDIS_SONAME 1.
1.1
-dev
/* Connection type can be blocking or non-blocking and is set in the
/* Connection type can be blocking or non-blocking and is set in the
* least significant bit of the flags field in redisContext. */
* least significant bit of the flags field in redisContext. */
...
@@ -92,6 +92,11 @@ typedef long long ssize_t;
...
@@ -92,6 +92,11 @@ typedef long long ssize_t;
/* Flag that indicates the user does not want replies to be automatically freed */
/* Flag that indicates the user does not want replies to be automatically freed */
#define REDIS_NO_AUTO_FREE_REPLIES 0x400
#define REDIS_NO_AUTO_FREE_REPLIES 0x400
/* Flags to prefer IPv6 or IPv4 when doing DNS lookup. (If both are set,
* AF_UNSPEC is used.) */
#define REDIS_PREFER_IPV4 0x800
#define REDIS_PREFER_IPV6 0x1000
#define REDIS_KEEPALIVE_INTERVAL 15
/* seconds */
#define REDIS_KEEPALIVE_INTERVAL 15
/* seconds */
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
...
@@ -149,20 +154,17 @@ struct redisSsl;
...
@@ -149,20 +154,17 @@ struct redisSsl;
#define REDIS_OPT_NONBLOCK 0x01
#define REDIS_OPT_NONBLOCK 0x01
#define REDIS_OPT_REUSEADDR 0x02
#define REDIS_OPT_REUSEADDR 0x02
#define REDIS_OPT_NOAUTOFREE 0x04
/* Don't automatically free the async
/**
* object on a connection failure, or
* Don't automatically free the async object on a connection failure,
* other implicit conditions. Only free
* or other implicit conditions. Only free on an explicit call to disconnect() or free()
* on an explicit call to disconnect()
*/
* or free() */
#define REDIS_OPT_NOAUTOFREE 0x04
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
/* Don't automatically intercept and
* free RESP3 PUSH replies. */
/* Don't automatically intercept and free RESP3 PUSH replies. */
#define REDIS_OPT_NOAUTOFREEREPLIES 0x10
/* Don't automatically free replies. */
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
#define REDIS_OPT_PREFER_IPV4 0x20
/* Prefer IPv4 in DNS lookups. */
#define REDIS_OPT_PREFER_IPV6 0x40
/* Prefer IPv6 in DNS lookups. */
/**
#define REDIS_OPT_PREFER_IP_UNSPEC (REDIS_OPT_PREFER_IPV4 | REDIS_OPT_PREFER_IPV6)
* Don't automatically free replies
*/
#define REDIS_OPT_NOAUTOFREEREPLIES 0x10
/* In Unix systems a file descriptor is a regular signed int, with -1
/* In Unix systems a file descriptor is a regular signed int, with -1
* representing an invalid descriptor. In Windows it is a SOCKET
* representing an invalid descriptor. In Windows it is a SOCKET
...
@@ -220,27 +222,37 @@ typedef struct {
...
@@ -220,27 +222,37 @@ typedef struct {
/**
/**
* Helper macros to initialize options to their specified fields.
* Helper macros to initialize options to their specified fields.
*/
*/
#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \
#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) do { \
(opts)->type = REDIS_CONN_TCP; \
(opts)->type = REDIS_CONN_TCP; \
(opts)->endpoint.tcp.ip = ip_; \
(opts)->endpoint.tcp.ip = ip_; \
(opts)->endpoint.tcp.port = port_;
(opts)->endpoint.tcp.port = port_; \
} while(0)
#define REDIS_OPTIONS_SET_UNIX(opts, path) \
(opts)->type = REDIS_CONN_UNIX; \
#define REDIS_OPTIONS_SET_UNIX(opts, path) do { \
(opts)->endpoint.unix_socket = path;
(opts)->type = REDIS_CONN_UNIX; \
(opts)->endpoint.unix_socket = path; \
#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \
} while(0)
(opts)->privdata = data; \
(opts)->free_privdata = dtor; \
#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) do { \
(opts)->privdata = data; \
(opts)->free_privdata = dtor; \
} while(0)
typedef
struct
redisContextFuncs
{
typedef
struct
redisContextFuncs
{
void
(
*
close
)(
struct
redisContext
*
);
void
(
*
free_privctx
)(
void
*
);
void
(
*
free_privctx
)(
void
*
);
void
(
*
async_read
)(
struct
redisAsyncContext
*
);
void
(
*
async_read
)(
struct
redisAsyncContext
*
);
void
(
*
async_write
)(
struct
redisAsyncContext
*
);
void
(
*
async_write
)(
struct
redisAsyncContext
*
);
/* Read/Write data to the underlying communication stream, returning the
* number of bytes read/written. In the event of an unrecoverable error
* these functions shall return a value < 0. In the event of a
* recoverable error, they should return 0. */
ssize_t
(
*
read
)(
struct
redisContext
*
,
char
*
,
size_t
);
ssize_t
(
*
read
)(
struct
redisContext
*
,
char
*
,
size_t
);
ssize_t
(
*
write
)(
struct
redisContext
*
);
ssize_t
(
*
write
)(
struct
redisContext
*
);
}
redisContextFuncs
;
}
redisContextFuncs
;
/* Context for a connection to Redis */
/* Context for a connection to Redis */
typedef
struct
redisContext
{
typedef
struct
redisContext
{
const
redisContextFuncs
*
funcs
;
/* Function table */
const
redisContextFuncs
*
funcs
;
/* Function table */
...
@@ -310,6 +322,8 @@ int redisReconnect(redisContext *c);
...
@@ -310,6 +322,8 @@ int redisReconnect(redisContext *c);
redisPushFn
*
redisSetPushCallback
(
redisContext
*
c
,
redisPushFn
*
fn
);
redisPushFn
*
redisSetPushCallback
(
redisContext
*
c
,
redisPushFn
*
fn
);
int
redisSetTimeout
(
redisContext
*
c
,
const
struct
timeval
tv
);
int
redisSetTimeout
(
redisContext
*
c
,
const
struct
timeval
tv
);
int
redisEnableKeepAlive
(
redisContext
*
c
);
int
redisEnableKeepAlive
(
redisContext
*
c
);
int
redisEnableKeepAliveWithInterval
(
redisContext
*
c
,
int
interval
);
int
redisSetTcpUserTimeout
(
redisContext
*
c
,
unsigned
int
timeout
);
void
redisFree
(
redisContext
*
c
);
void
redisFree
(
redisContext
*
c
);
redisFD
redisFreeKeepFd
(
redisContext
*
c
);
redisFD
redisFreeKeepFd
(
redisContext
*
c
);
int
redisBufferRead
(
redisContext
*
c
);
int
redisBufferRead
(
redisContext
*
c
);
...
...
deps/hiredis/hiredis.pc.in
View file @
2eaf2360
...
@@ -9,4 +9,4 @@ Name: hiredis
...
@@ -9,4 +9,4 @@ Name: hiredis
Description: Minimalistic C client library for Redis.
Description: Minimalistic C client library for Redis.
Version: @PROJECT_VERSION@
Version: @PROJECT_VERSION@
Libs: -L${libdir} -lhiredis
Libs: -L${libdir} -lhiredis
Cflags: -I${pkgincludedir} -D_FILE_OFFSET_BITS=64
Cflags: -I${pkgincludedir}
-I${includedir}
-D_FILE_OFFSET_BITS=64
deps/hiredis/hiredis_ssl-config.cmake.in
View file @
2eaf2360
...
@@ -2,6 +2,9 @@
...
@@ -2,6 +2,9 @@
set_and_check(hiredis_ssl_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(hiredis_ssl_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
include(CMakeFindDependencyMacro)
find_dependency(OpenSSL)
IF (NOT TARGET hiredis::hiredis_ssl)
IF (NOT TARGET hiredis::hiredis_ssl)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis_ssl-targets.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis_ssl-targets.cmake)
ENDIF()
ENDIF()
...
...
deps/hiredis/hiredis_ssl.h
View file @
2eaf2360
...
@@ -56,11 +56,33 @@ typedef enum {
...
@@ -56,11 +56,33 @@ typedef enum {
REDIS_SSL_CTX_CERT_KEY_REQUIRED
,
/* Client cert and key must both be specified or skipped */
REDIS_SSL_CTX_CERT_KEY_REQUIRED
,
/* Client cert and key must both be specified or skipped */
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
,
/* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
,
/* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
,
/* Failed to load client certificate */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
,
/* Failed to load client certificate */
REDIS_SSL_CTX_CLIENT_DEFAULT_CERT_FAILED
,
/* Failed to set client default certificate directory */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
,
/* Failed to load private key */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
,
/* Failed to load private key */
REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED
,
/* Failed to open system certificate store */
REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED
,
/* Failed to open system certificate store */
REDIS_SSL_CTX_OS_CERT_ADD_FAILED
/* Failed to add CA certificates obtained from system to the SSL context */
REDIS_SSL_CTX_OS_CERT_ADD_FAILED
/* Failed to add CA certificates obtained from system to the SSL context */
}
redisSSLContextError
;
}
redisSSLContextError
;
/* Constants that mirror OpenSSL's verify modes. By default,
* REDIS_SSL_VERIFY_PEER is used with redisCreateSSLContext().
* Some Redis clients disable peer verification if there are no
* certificates specified.
*/
#define REDIS_SSL_VERIFY_NONE 0x00
#define REDIS_SSL_VERIFY_PEER 0x01
#define REDIS_SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
#define REDIS_SSL_VERIFY_CLIENT_ONCE 0x04
#define REDIS_SSL_VERIFY_POST_HANDSHAKE 0x08
/* Options to create an OpenSSL context. */
typedef
struct
{
const
char
*
cacert_filename
;
const
char
*
capath
;
const
char
*
cert_filename
;
const
char
*
private_key_filename
;
const
char
*
server_name
;
int
verify_mode
;
}
redisSSLOptions
;
/**
/**
* Return the error message corresponding with the specified error code.
* Return the error message corresponding with the specified error code.
*/
*/
...
@@ -101,6 +123,18 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
...
@@ -101,6 +123,18 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
server_name
,
redisSSLContextError
*
error
);
const
char
*
server_name
,
redisSSLContextError
*
error
);
/**
* Helper function to initialize an OpenSSL context that can be used
* to initiate SSL connections. This is a more extensible version of redisCreateSSLContext().
*
* options contains a structure of SSL options to use.
*
* If error is non-null, it will be populated in case the context creation fails
* (returning a NULL).
*/
redisSSLContext
*
redisCreateSSLContextWithOptions
(
redisSSLOptions
*
options
,
redisSSLContextError
*
error
);
/**
/**
* Free a previously created OpenSSL context.
* Free a previously created OpenSSL context.
*/
*/
...
...
deps/hiredis/hiredis_ssl.pc.in
View file @
2eaf2360
prefix=@CMAKE_INSTALL_PREFIX@
prefix=@CMAKE_INSTALL_PREFIX@
install_libdir=@CMAKE_INSTALL_LIBDIR@
exec_prefix=${prefix}
exec_prefix=${prefix}
libdir=${exec_prefix}/
lib
libdir=${exec_prefix}/
${install_libdir}
includedir=${prefix}/include
includedir=${prefix}/include
pkgincludedir=${includedir}/hiredis
pkgincludedir=${includedir}/hiredis
...
...
deps/hiredis/net.c
View file @
2eaf2360
...
@@ -50,6 +50,8 @@
...
@@ -50,6 +50,8 @@
/* Defined in hiredis.c */
/* Defined in hiredis.c */
void
__redisSetError
(
redisContext
*
c
,
int
type
,
const
char
*
str
);
void
__redisSetError
(
redisContext
*
c
,
int
type
,
const
char
*
str
);
int
redisContextUpdateCommandTimeout
(
redisContext
*
c
,
const
struct
timeval
*
timeout
);
void
redisNetClose
(
redisContext
*
c
)
{
void
redisNetClose
(
redisContext
*
c
)
{
if
(
c
&&
c
->
fd
!=
REDIS_INVALID_FD
)
{
if
(
c
&&
c
->
fd
!=
REDIS_INVALID_FD
)
{
close
(
c
->
fd
);
close
(
c
->
fd
);
...
@@ -68,7 +70,7 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
...
@@ -68,7 +70,7 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
__redisSetError
(
c
,
REDIS_ERR_TIMEOUT
,
"recv timeout"
);
__redisSetError
(
c
,
REDIS_ERR_TIMEOUT
,
"recv timeout"
);
return
-
1
;
return
-
1
;
}
else
{
}
else
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
__redisSetError
(
c
,
REDIS_ERR_IO
,
strerror
(
errno
)
);
return
-
1
;
return
-
1
;
}
}
}
else
if
(
nread
==
0
)
{
}
else
if
(
nread
==
0
)
{
...
@@ -80,15 +82,19 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
...
@@ -80,15 +82,19 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
}
}
ssize_t
redisNetWrite
(
redisContext
*
c
)
{
ssize_t
redisNetWrite
(
redisContext
*
c
)
{
ssize_t
nwritten
=
send
(
c
->
fd
,
c
->
obuf
,
hi_sdslen
(
c
->
obuf
),
0
);
ssize_t
nwritten
;
nwritten
=
send
(
c
->
fd
,
c
->
obuf
,
hi_sdslen
(
c
->
obuf
),
0
);
if
(
nwritten
<
0
)
{
if
(
nwritten
<
0
)
{
if
((
errno
==
EWOULDBLOCK
&&
!
(
c
->
flags
&
REDIS_BLOCK
))
||
(
errno
==
EINTR
))
{
if
((
errno
==
EWOULDBLOCK
&&
!
(
c
->
flags
&
REDIS_BLOCK
))
||
(
errno
==
EINTR
))
{
/* Try again later */
/* Try again */
return
0
;
}
else
{
}
else
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
__redisSetError
(
c
,
REDIS_ERR_IO
,
strerror
(
errno
)
);
return
-
1
;
return
-
1
;
}
}
}
}
return
nwritten
;
return
nwritten
;
}
}
...
@@ -166,6 +172,7 @@ int redisKeepAlive(redisContext *c, int interval) {
...
@@ -166,6 +172,7 @@ int redisKeepAlive(redisContext *c, int interval) {
int
val
=
1
;
int
val
=
1
;
redisFD
fd
=
c
->
fd
;
redisFD
fd
=
c
->
fd
;
#ifndef _WIN32
if
(
setsockopt
(
fd
,
SOL_SOCKET
,
SO_KEEPALIVE
,
&
val
,
sizeof
(
val
))
==
-
1
){
if
(
setsockopt
(
fd
,
SOL_SOCKET
,
SO_KEEPALIVE
,
&
val
,
sizeof
(
val
))
==
-
1
){
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
strerror
(
errno
));
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
strerror
(
errno
));
return
REDIS_ERR
;
return
REDIS_ERR
;
...
@@ -199,7 +206,15 @@ int redisKeepAlive(redisContext *c, int interval) {
...
@@ -199,7 +206,15 @@ int redisKeepAlive(redisContext *c, int interval) {
}
}
#endif
#endif
#endif
#endif
#else
int
res
;
res
=
win32_redisKeepAlive
(
fd
,
interval
*
1000
);
if
(
res
!=
0
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
strerror
(
res
));
return
REDIS_ERR
;
}
#endif
return
REDIS_OK
;
return
REDIS_OK
;
}
}
...
@@ -213,6 +228,22 @@ int redisSetTcpNoDelay(redisContext *c) {
...
@@ -213,6 +228,22 @@ int redisSetTcpNoDelay(redisContext *c) {
return
REDIS_OK
;
return
REDIS_OK
;
}
}
int
redisContextSetTcpUserTimeout
(
redisContext
*
c
,
unsigned
int
timeout
)
{
int
res
;
#ifdef TCP_USER_TIMEOUT
res
=
setsockopt
(
c
->
fd
,
IPPROTO_TCP
,
TCP_USER_TIMEOUT
,
&
timeout
,
sizeof
(
timeout
));
#else
res
=
-
1
;
(
void
)
timeout
;
#endif
if
(
res
==
-
1
)
{
__redisSetErrorFromErrno
(
c
,
REDIS_ERR_IO
,
"setsockopt(TCP_USER_TIMEOUT)"
);
redisNetClose
(
c
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
}
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
static
int
redisContextTimeoutMsec
(
redisContext
*
c
,
long
*
result
)
static
int
redisContextTimeoutMsec
(
redisContext
*
c
,
long
*
result
)
...
@@ -223,6 +254,7 @@ static int redisContextTimeoutMsec(redisContext *c, long *result)
...
@@ -223,6 +254,7 @@ static int redisContextTimeoutMsec(redisContext *c, long *result)
/* Only use timeout when not NULL. */
/* Only use timeout when not NULL. */
if
(
timeout
!=
NULL
)
{
if
(
timeout
!=
NULL
)
{
if
(
timeout
->
tv_usec
>
1000000
||
timeout
->
tv_sec
>
__MAX_MSEC
)
{
if
(
timeout
->
tv_usec
>
1000000
||
timeout
->
tv_sec
>
__MAX_MSEC
)
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
"Invalid timeout specified"
);
*
result
=
msec
;
*
result
=
msec
;
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
...
@@ -277,12 +309,28 @@ int redisCheckConnectDone(redisContext *c, int *completed) {
...
@@ -277,12 +309,28 @@ int redisCheckConnectDone(redisContext *c, int *completed) {
*
completed
=
1
;
*
completed
=
1
;
return
REDIS_OK
;
return
REDIS_OK
;
}
}
switch
(
errno
)
{
int
error
=
errno
;
if
(
error
==
EINPROGRESS
)
{
/* must check error to see if connect failed. Get the socket error */
int
fail
,
so_error
;
socklen_t
optlen
=
sizeof
(
so_error
);
fail
=
getsockopt
(
c
->
fd
,
SOL_SOCKET
,
SO_ERROR
,
&
so_error
,
&
optlen
);
if
(
fail
==
0
)
{
if
(
so_error
==
0
)
{
/* Socket is connected! */
*
completed
=
1
;
return
REDIS_OK
;
}
/* connection error; */
errno
=
so_error
;
error
=
so_error
;
}
}
switch
(
error
)
{
case
EISCONN
:
case
EISCONN
:
*
completed
=
1
;
*
completed
=
1
;
return
REDIS_OK
;
return
REDIS_OK
;
case
EALREADY
:
case
EALREADY
:
case
EINPROGRESS
:
case
EWOULDBLOCK
:
case
EWOULDBLOCK
:
*
completed
=
0
;
*
completed
=
0
;
return
REDIS_OK
;
return
REDIS_OK
;
...
@@ -317,6 +365,10 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
...
@@ -317,6 +365,10 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
const
void
*
to_ptr
=
&
tv
;
const
void
*
to_ptr
=
&
tv
;
size_t
to_sz
=
sizeof
(
tv
);
size_t
to_sz
=
sizeof
(
tv
);
if
(
redisContextUpdateCommandTimeout
(
c
,
&
tv
)
!=
REDIS_OK
)
{
__redisSetError
(
c
,
REDIS_ERR_OOM
,
"Out of memory"
);
return
REDIS_ERR
;
}
if
(
setsockopt
(
c
->
fd
,
SOL_SOCKET
,
SO_RCVTIMEO
,
to_ptr
,
to_sz
)
==
-
1
)
{
if
(
setsockopt
(
c
->
fd
,
SOL_SOCKET
,
SO_RCVTIMEO
,
to_ptr
,
to_sz
)
==
-
1
)
{
__redisSetErrorFromErrno
(
c
,
REDIS_ERR_IO
,
"setsockopt(SO_RCVTIMEO)"
);
__redisSetErrorFromErrno
(
c
,
REDIS_ERR_IO
,
"setsockopt(SO_RCVTIMEO)"
);
return
REDIS_ERR
;
return
REDIS_ERR
;
...
@@ -400,7 +452,6 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
...
@@ -400,7 +452,6 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
}
}
if
(
redisContextTimeoutMsec
(
c
,
&
timeout_msec
)
!=
REDIS_OK
)
{
if
(
redisContextTimeoutMsec
(
c
,
&
timeout_msec
)
!=
REDIS_OK
)
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
"Invalid timeout specified"
);
goto
error
;
goto
error
;
}
}
...
@@ -417,17 +468,25 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
...
@@ -417,17 +468,25 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
hints
.
ai_family
=
AF_INET
;
hints
.
ai_family
=
AF_INET
;
hints
.
ai_socktype
=
SOCK_STREAM
;
hints
.
ai_socktype
=
SOCK_STREAM
;
/* Try with IPv6 if no IPv4 address was found. We do it in this order since
/* DNS lookup. To use dual stack, set both flags to prefer both IPv4 and
* in a Redis client you can't afford to test if you have IPv6 connectivity
* IPv6. By default, for historical reasons, we try IPv4 first and then we
* as this would add latency to every connect. Otherwise a more sensible
* try IPv6 only if no IPv4 address was found. */
* route could be: Use IPv6 if both addresses are available and there is IPv6
if
(
c
->
flags
&
REDIS_PREFER_IPV6
&&
c
->
flags
&
REDIS_PREFER_IPV4
)
* connectivity. */
hints
.
ai_family
=
AF_UNSPEC
;
if
((
rv
=
getaddrinfo
(
c
->
tcp
.
host
,
_port
,
&
hints
,
&
servinfo
))
!=
0
)
{
else
if
(
c
->
flags
&
REDIS_PREFER_IPV6
)
hints
.
ai_family
=
AF_INET6
;
hints
.
ai_family
=
AF_INET6
;
if
((
rv
=
getaddrinfo
(
addr
,
_port
,
&
hints
,
&
servinfo
))
!=
0
)
{
else
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
gai_strerror
(
rv
));
hints
.
ai_family
=
AF_INET
;
return
REDIS_ERR
;
}
rv
=
getaddrinfo
(
c
->
tcp
.
host
,
_port
,
&
hints
,
&
servinfo
);
if
(
rv
!=
0
&&
hints
.
ai_family
!=
AF_UNSPEC
)
{
/* Try again with the other IP version. */
hints
.
ai_family
=
(
hints
.
ai_family
==
AF_INET
)
?
AF_INET6
:
AF_INET
;
rv
=
getaddrinfo
(
c
->
tcp
.
host
,
_port
,
&
hints
,
&
servinfo
);
}
if
(
rv
!=
0
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
gai_strerror
(
rv
));
return
REDIS_ERR
;
}
}
for
(
p
=
servinfo
;
p
!=
NULL
;
p
=
p
->
ai_next
)
{
for
(
p
=
servinfo
;
p
!=
NULL
;
p
=
p
->
ai_next
)
{
addrretry:
addrretry:
...
...
deps/hiredis/net.h
View file @
2eaf2360
...
@@ -52,5 +52,6 @@ int redisKeepAlive(redisContext *c, int interval);
...
@@ -52,5 +52,6 @@ int redisKeepAlive(redisContext *c, int interval);
int
redisCheckConnectDone
(
redisContext
*
c
,
int
*
completed
);
int
redisCheckConnectDone
(
redisContext
*
c
,
int
*
completed
);
int
redisSetTcpNoDelay
(
redisContext
*
c
);
int
redisSetTcpNoDelay
(
redisContext
*
c
);
int
redisContextSetTcpUserTimeout
(
redisContext
*
c
,
unsigned
int
timeout
);
#endif
#endif
deps/hiredis/read.c
View file @
2eaf2360
...
@@ -303,11 +303,14 @@ static int processLineItem(redisReader *r) {
...
@@ -303,11 +303,14 @@ static int processLineItem(redisReader *r) {
d
=
INFINITY
;
/* Positive infinite. */
d
=
INFINITY
;
/* Positive infinite. */
}
else
if
(
len
==
4
&&
strcasecmp
(
buf
,
"-inf"
)
==
0
)
{
}
else
if
(
len
==
4
&&
strcasecmp
(
buf
,
"-inf"
)
==
0
)
{
d
=
-
INFINITY
;
/* Negative infinite. */
d
=
-
INFINITY
;
/* Negative infinite. */
}
else
if
((
len
==
3
&&
strcasecmp
(
buf
,
"nan"
)
==
0
)
||
(
len
==
4
&&
strcasecmp
(
buf
,
"-nan"
)
==
0
))
{
d
=
NAN
;
/* nan. */
}
else
{
}
else
{
d
=
strtod
((
char
*
)
buf
,
&
eptr
);
d
=
strtod
((
char
*
)
buf
,
&
eptr
);
/* RESP3 only allows "inf", "-inf", and finite values, while
/* RESP3 only allows "inf", "-inf", and finite values, while
* strtod() allows other variations on infinity,
NaN,
* strtod() allows other variations on infinity,
* etc. We explicity handle our two allowed infinite cases
* etc. We explicity handle our two allowed infinite cases
and NaN
* above, so strtod() should only result in finite values. */
* above, so strtod() should only result in finite values. */
if
(
buf
[
0
]
==
'\0'
||
eptr
!=
&
buf
[
len
]
||
!
isfinite
(
d
))
{
if
(
buf
[
0
]
==
'\0'
||
eptr
!=
&
buf
[
len
]
||
!
isfinite
(
d
))
{
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
...
@@ -374,7 +377,7 @@ static int processLineItem(redisReader *r) {
...
@@ -374,7 +377,7 @@ static int processLineItem(redisReader *r) {
if
(
r
->
fn
&&
r
->
fn
->
createString
)
if
(
r
->
fn
&&
r
->
fn
->
createString
)
obj
=
r
->
fn
->
createString
(
cur
,
p
,
len
);
obj
=
r
->
fn
->
createString
(
cur
,
p
,
len
);
else
else
obj
=
(
void
*
)(
size
_t
)(
cur
->
type
);
obj
=
(
void
*
)(
uintptr
_t
)(
cur
->
type
);
}
}
if
(
obj
==
NULL
)
{
if
(
obj
==
NULL
)
{
...
@@ -439,7 +442,7 @@ static int processBulkItem(redisReader *r) {
...
@@ -439,7 +442,7 @@ static int processBulkItem(redisReader *r) {
if
(
r
->
fn
&&
r
->
fn
->
createString
)
if
(
r
->
fn
&&
r
->
fn
->
createString
)
obj
=
r
->
fn
->
createString
(
cur
,
s
+
2
,
len
);
obj
=
r
->
fn
->
createString
(
cur
,
s
+
2
,
len
);
else
else
obj
=
(
void
*
)(
long
)
cur
->
type
;
obj
=
(
void
*
)(
uintptr_t
)
cur
->
type
;
success
=
1
;
success
=
1
;
}
}
}
}
...
@@ -536,7 +539,7 @@ static int processAggregateItem(redisReader *r) {
...
@@ -536,7 +539,7 @@ static int processAggregateItem(redisReader *r) {
if
(
r
->
fn
&&
r
->
fn
->
createArray
)
if
(
r
->
fn
&&
r
->
fn
->
createArray
)
obj
=
r
->
fn
->
createArray
(
cur
,
elements
);
obj
=
r
->
fn
->
createArray
(
cur
,
elements
);
else
else
obj
=
(
void
*
)(
long
)
cur
->
type
;
obj
=
(
void
*
)(
uintptr_t
)
cur
->
type
;
if
(
obj
==
NULL
)
{
if
(
obj
==
NULL
)
{
__redisReaderSetErrorOOM
(
r
);
__redisReaderSetErrorOOM
(
r
);
...
...
deps/hiredis/sds.c
View file @
2eaf2360
...
@@ -90,6 +90,7 @@ hisds hi_sdsnewlen(const void *init, size_t initlen) {
...
@@ -90,6 +90,7 @@ hisds hi_sdsnewlen(const void *init, size_t initlen) {
int
hdrlen
=
hi_sdsHdrSize
(
type
);
int
hdrlen
=
hi_sdsHdrSize
(
type
);
unsigned
char
*
fp
;
/* flags pointer. */
unsigned
char
*
fp
;
/* flags pointer. */
if
(
hdrlen
+
initlen
+
1
<=
initlen
)
return
NULL
;
/* Catch size_t overflow */
sh
=
hi_s_malloc
(
hdrlen
+
initlen
+
1
);
sh
=
hi_s_malloc
(
hdrlen
+
initlen
+
1
);
if
(
sh
==
NULL
)
return
NULL
;
if
(
sh
==
NULL
)
return
NULL
;
if
(
!
init
)
if
(
!
init
)
...
@@ -174,7 +175,7 @@ void hi_sdsfree(hisds s) {
...
@@ -174,7 +175,7 @@ void hi_sdsfree(hisds s) {
* the output will be "6" as the string was modified but the logical length
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
* remains 6 bytes. */
void
hi_sdsupdatelen
(
hisds
s
)
{
void
hi_sdsupdatelen
(
hisds
s
)
{
in
t
reallen
=
strlen
(
s
);
size_
t
reallen
=
strlen
(
s
);
hi_sdssetlen
(
s
,
reallen
);
hi_sdssetlen
(
s
,
reallen
);
}
}
...
@@ -196,7 +197,7 @@ void hi_sdsclear(hisds s) {
...
@@ -196,7 +197,7 @@ void hi_sdsclear(hisds s) {
hisds
hi_sdsMakeRoomFor
(
hisds
s
,
size_t
addlen
)
{
hisds
hi_sdsMakeRoomFor
(
hisds
s
,
size_t
addlen
)
{
void
*
sh
,
*
newsh
;
void
*
sh
,
*
newsh
;
size_t
avail
=
hi_sdsavail
(
s
);
size_t
avail
=
hi_sdsavail
(
s
);
size_t
len
,
newlen
;
size_t
len
,
newlen
,
reqlen
;
char
type
,
oldtype
=
s
[
-
1
]
&
HI_SDS_TYPE_MASK
;
char
type
,
oldtype
=
s
[
-
1
]
&
HI_SDS_TYPE_MASK
;
int
hdrlen
;
int
hdrlen
;
...
@@ -205,7 +206,8 @@ hisds hi_sdsMakeRoomFor(hisds s, size_t addlen) {
...
@@ -205,7 +206,8 @@ hisds hi_sdsMakeRoomFor(hisds s, size_t addlen) {
len
=
hi_sdslen
(
s
);
len
=
hi_sdslen
(
s
);
sh
=
(
char
*
)
s
-
hi_sdsHdrSize
(
oldtype
);
sh
=
(
char
*
)
s
-
hi_sdsHdrSize
(
oldtype
);
newlen
=
(
len
+
addlen
);
reqlen
=
newlen
=
(
len
+
addlen
);
if
(
newlen
<=
len
)
return
NULL
;
/* Catch size_t overflow */
if
(
newlen
<
HI_SDS_MAX_PREALLOC
)
if
(
newlen
<
HI_SDS_MAX_PREALLOC
)
newlen
*=
2
;
newlen
*=
2
;
else
else
...
@@ -219,6 +221,7 @@ hisds hi_sdsMakeRoomFor(hisds s, size_t addlen) {
...
@@ -219,6 +221,7 @@ hisds hi_sdsMakeRoomFor(hisds s, size_t addlen) {
if
(
type
==
HI_SDS_TYPE_5
)
type
=
HI_SDS_TYPE_8
;
if
(
type
==
HI_SDS_TYPE_5
)
type
=
HI_SDS_TYPE_8
;
hdrlen
=
hi_sdsHdrSize
(
type
);
hdrlen
=
hi_sdsHdrSize
(
type
);
if
(
hdrlen
+
newlen
+
1
<=
reqlen
)
return
NULL
;
/* Catch size_t overflow */
if
(
oldtype
==
type
)
{
if
(
oldtype
==
type
)
{
newsh
=
hi_s_realloc
(
sh
,
hdrlen
+
newlen
+
1
);
newsh
=
hi_s_realloc
(
sh
,
hdrlen
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
if
(
newsh
==
NULL
)
return
NULL
;
...
@@ -580,7 +583,7 @@ hisds hi_sdscatprintf(hisds s, const char *fmt, ...) {
...
@@ -580,7 +583,7 @@ hisds hi_sdscatprintf(hisds s, const char *fmt, ...) {
*/
*/
hisds
hi_sdscatfmt
(
hisds
s
,
char
const
*
fmt
,
...)
{
hisds
hi_sdscatfmt
(
hisds
s
,
char
const
*
fmt
,
...)
{
const
char
*
f
=
fmt
;
const
char
*
f
=
fmt
;
int
i
;
long
i
;
va_list
ap
;
va_list
ap
;
va_start
(
ap
,
fmt
);
va_start
(
ap
,
fmt
);
...
@@ -753,16 +756,16 @@ int hi_sdsrange(hisds s, ssize_t start, ssize_t end) {
...
@@ -753,16 +756,16 @@ int hi_sdsrange(hisds s, ssize_t start, ssize_t end) {
return
0
;
return
0
;
}
}
/* Apply tolower() to every character of the
hi
sds string 's'. */
/* Apply tolower() to every character of the sds string 's'. */
void
hi_sdstolower
(
hisds
s
)
{
void
hi_sdstolower
(
hisds
s
)
{
in
t
len
=
hi_sdslen
(
s
),
j
;
size_
t
len
=
hi_sdslen
(
s
),
j
;
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
tolower
(
s
[
j
]);
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
tolower
(
s
[
j
]);
}
}
/* Apply toupper() to every character of the
hi
sds string 's'. */
/* Apply toupper() to every character of the sds string 's'. */
void
hi_sdstoupper
(
hisds
s
)
{
void
hi_sdstoupper
(
hisds
s
)
{
in
t
len
=
hi_sdslen
(
s
),
j
;
size_
t
len
=
hi_sdslen
(
s
),
j
;
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
toupper
(
s
[
j
]);
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
toupper
(
s
[
j
]);
}
}
...
...
deps/hiredis/sds.h
View file @
2eaf2360
...
@@ -35,9 +35,11 @@
...
@@ -35,9 +35,11 @@
#define HI_SDS_MAX_PREALLOC (1024*1024)
#define HI_SDS_MAX_PREALLOC (1024*1024)
#ifdef _MSC_VER
#ifdef _MSC_VER
#define __attribute__(x)
typedef
long
long
ssize_t
;
typedef
long
long
ssize_t
;
#define SSIZE_MAX (LLONG_MAX >> 1)
#define SSIZE_MAX (LLONG_MAX >> 1)
#ifndef __clang__
#define __attribute__(x)
#endif
#endif
#endif
#include <sys/types.h>
#include <sys/types.h>
...
...
deps/hiredis/sockcompat.c
View file @
2eaf2360
...
@@ -180,10 +180,17 @@ int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen)
...
@@ -180,10 +180,17 @@ int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen)
/* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as
/* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as
* EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX
* EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX
* logic consistent. */
* logic consistent.
if
(
errno
==
EWOULDBLOCK
)
{
* Additionally, WSAALREADY is can be reported as WSAEINVAL to and this is
* translated to EIO. Convert appropriately
*/
int
err
=
errno
;
if
(
err
==
EWOULDBLOCK
)
{
errno
=
EINPROGRESS
;
errno
=
EINPROGRESS
;
}
}
else
if
(
err
==
EIO
)
{
errno
=
EALREADY
;
}
return
ret
!=
SOCKET_ERROR
?
ret
:
-
1
;
return
ret
!=
SOCKET_ERROR
?
ret
:
-
1
;
}
}
...
@@ -205,6 +212,14 @@ int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, sockle
...
@@ -205,6 +212,14 @@ int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, sockle
}
else
{
}
else
{
ret
=
getsockopt
(
sockfd
,
level
,
optname
,
(
char
*
)
optval
,
optlen
);
ret
=
getsockopt
(
sockfd
,
level
,
optname
,
(
char
*
)
optval
,
optlen
);
}
}
if
(
ret
!=
SOCKET_ERROR
&&
level
==
SOL_SOCKET
&&
optname
==
SO_ERROR
)
{
/* translate SO_ERROR codes, if non-zero */
int
err
=
*
(
int
*
)
optval
;
if
(
err
!=
0
)
{
err
=
_wsaErrorToErrno
(
err
);
*
(
int
*
)
optval
=
err
;
}
}
_updateErrno
(
ret
!=
SOCKET_ERROR
);
_updateErrno
(
ret
!=
SOCKET_ERROR
);
return
ret
!=
SOCKET_ERROR
?
ret
:
-
1
;
return
ret
!=
SOCKET_ERROR
?
ret
:
-
1
;
}
}
...
@@ -245,4 +260,21 @@ int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
...
@@ -245,4 +260,21 @@ int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
_updateErrno
(
ret
!=
SOCKET_ERROR
);
_updateErrno
(
ret
!=
SOCKET_ERROR
);
return
ret
!=
SOCKET_ERROR
?
ret
:
-
1
;
return
ret
!=
SOCKET_ERROR
?
ret
:
-
1
;
}
}
int
win32_redisKeepAlive
(
SOCKET
sockfd
,
int
interval_ms
)
{
struct
tcp_keepalive
cfg
;
DWORD
bytes_in
;
int
res
;
cfg
.
onoff
=
1
;
cfg
.
keepaliveinterval
=
interval_ms
;
cfg
.
keepalivetime
=
interval_ms
;
res
=
WSAIoctl
(
sockfd
,
SIO_KEEPALIVE_VALS
,
&
cfg
,
sizeof
(
struct
tcp_keepalive
),
NULL
,
0
,
&
bytes_in
,
NULL
,
NULL
);
return
res
==
0
?
0
:
_wsaErrorToErrno
(
res
);
}
#endif
/* _WIN32 */
#endif
/* _WIN32 */
deps/hiredis/sockcompat.h
View file @
2eaf2360
...
@@ -50,6 +50,7 @@
...
@@ -50,6 +50,7 @@
#include <ws2tcpip.h>
#include <ws2tcpip.h>
#include <stddef.h>
#include <stddef.h>
#include <errno.h>
#include <errno.h>
#include <mstcpip.h>
#ifdef _MSC_VER
#ifdef _MSC_VER
typedef
long
long
ssize_t
;
typedef
long
long
ssize_t
;
...
@@ -71,6 +72,8 @@ ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
...
@@ -71,6 +72,8 @@ ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
typedef
ULONG
nfds_t
;
typedef
ULONG
nfds_t
;
int
win32_poll
(
struct
pollfd
*
fds
,
nfds_t
nfds
,
int
timeout
);
int
win32_poll
(
struct
pollfd
*
fds
,
nfds_t
nfds
,
int
timeout
);
int
win32_redisKeepAlive
(
SOCKET
sockfd
,
int
interval_ms
);
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
#undef gai_strerror
#undef gai_strerror
...
...
deps/hiredis/ssl.c
View file @
2eaf2360
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
#include "hiredis.h"
#include "hiredis.h"
#include "async.h"
#include "async.h"
#include "net.h"
#include <assert.h>
#include <assert.h>
#include <errno.h>
#include <errno.h>
...
@@ -39,6 +40,14 @@
...
@@ -39,6 +40,14 @@
#ifdef _WIN32
#ifdef _WIN32
#include <windows.h>
#include <windows.h>
#include <wincrypt.h>
#include <wincrypt.h>
#ifdef OPENSSL_IS_BORINGSSL
#undef X509_NAME
#undef X509_EXTENSIONS
#undef PKCS7_ISSUER_AND_SERIAL
#undef PKCS7_SIGNER_INFO
#undef OCSP_REQUEST
#undef OCSP_RESPONSE
#endif
#else
#else
#include <pthread.h>
#include <pthread.h>
#endif
#endif
...
@@ -219,6 +228,25 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
...
@@ -219,6 +228,25 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
server_name
,
redisSSLContextError
*
error
)
const
char
*
server_name
,
redisSSLContextError
*
error
)
{
{
redisSSLOptions
options
=
{
.
cacert_filename
=
cacert_filename
,
.
capath
=
capath
,
.
cert_filename
=
cert_filename
,
.
private_key_filename
=
private_key_filename
,
.
server_name
=
server_name
,
.
verify_mode
=
REDIS_SSL_VERIFY_PEER
,
};
return
redisCreateSSLContextWithOptions
(
&
options
,
error
);
}
redisSSLContext
*
redisCreateSSLContextWithOptions
(
redisSSLOptions
*
options
,
redisSSLContextError
*
error
)
{
const
char
*
cacert_filename
=
options
->
cacert_filename
;
const
char
*
capath
=
options
->
capath
;
const
char
*
cert_filename
=
options
->
cert_filename
;
const
char
*
private_key_filename
=
options
->
private_key_filename
;
const
char
*
server_name
=
options
->
server_name
;
#ifdef _WIN32
#ifdef _WIN32
HCERTSTORE
win_store
=
NULL
;
HCERTSTORE
win_store
=
NULL
;
PCCERT_CONTEXT
win_ctx
=
NULL
;
PCCERT_CONTEXT
win_ctx
=
NULL
;
...
@@ -235,7 +263,7 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
...
@@ -235,7 +263,7 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
}
}
SSL_CTX_set_options
(
ctx
->
ssl_ctx
,
SSL_OP_NO_SSLv2
|
SSL_OP_NO_SSLv3
);
SSL_CTX_set_options
(
ctx
->
ssl_ctx
,
SSL_OP_NO_SSLv2
|
SSL_OP_NO_SSLv3
);
SSL_CTX_set_verify
(
ctx
->
ssl_ctx
,
SSL_VERIFY_PEER
,
NULL
);
SSL_CTX_set_verify
(
ctx
->
ssl_ctx
,
options
->
verify_mode
,
NULL
);
if
((
cert_filename
!=
NULL
&&
private_key_filename
==
NULL
)
||
if
((
cert_filename
!=
NULL
&&
private_key_filename
==
NULL
)
||
(
private_key_filename
!=
NULL
&&
cert_filename
==
NULL
))
{
(
private_key_filename
!=
NULL
&&
cert_filename
==
NULL
))
{
...
@@ -273,6 +301,11 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
...
@@ -273,6 +301,11 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
if
(
error
)
*
error
=
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
;
if
(
error
)
*
error
=
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
;
goto
error
;
goto
error
;
}
}
}
else
{
if
(
!
SSL_CTX_set_default_verify_paths
(
ctx
->
ssl_ctx
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CLIENT_DEFAULT_CERT_FAILED
;
goto
error
;
}
}
}
if
(
cert_filename
)
{
if
(
cert_filename
)
{
...
@@ -560,6 +593,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
...
@@ -560,6 +593,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
}
}
redisContextFuncs
redisContextSSLFuncs
=
{
redisContextFuncs
redisContextSSLFuncs
=
{
.
close
=
redisNetClose
,
.
free_privctx
=
redisSSLFree
,
.
free_privctx
=
redisSSLFree
,
.
async_read
=
redisSSLAsyncRead
,
.
async_read
=
redisSSLAsyncRead
,
.
async_write
=
redisSSLAsyncWrite
,
.
async_write
=
redisSSLAsyncWrite
,
...
...
deps/hiredis/test.c
View file @
2eaf2360
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
#include "hiredis.h"
#include "hiredis.h"
#include "async.h"
#include "async.h"
#include "adapters/poll.h"
#ifdef HIREDIS_TEST_SSL
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#include "hiredis_ssl.h"
#endif
#endif
...
@@ -34,11 +35,11 @@ enum connection_type {
...
@@ -34,11 +35,11 @@ enum connection_type {
struct
config
{
struct
config
{
enum
connection_type
type
;
enum
connection_type
type
;
struct
timeval
connect_timeout
;
struct
{
struct
{
const
char
*
host
;
const
char
*
host
;
int
port
;
int
port
;
struct
timeval
timeout
;
}
tcp
;
}
tcp
;
struct
{
struct
{
...
@@ -75,6 +76,15 @@ static int tests = 0, fails = 0, skips = 0;
...
@@ -75,6 +76,15 @@ static int tests = 0, fails = 0, skips = 0;
#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;}
#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;}
#define test_skipped() { printf("\033[01;33mSKIPPED\033[0;0m\n"); skips++; }
#define test_skipped() { printf("\033[01;33mSKIPPED\033[0;0m\n"); skips++; }
static
void
millisleep
(
int
ms
)
{
#if _MSC_VER
Sleep
(
ms
);
#else
usleep
(
ms
*
1000
);
#endif
}
static
long
long
usec
(
void
)
{
static
long
long
usec
(
void
)
{
#ifndef _MSC_VER
#ifndef _MSC_VER
struct
timeval
tv
;
struct
timeval
tv
;
...
@@ -329,10 +339,14 @@ static void test_format_commands(void) {
...
@@ -329,10 +339,14 @@ static void test_format_commands(void) {
FLOAT_WIDTH_TEST
(
float
);
FLOAT_WIDTH_TEST
(
float
);
FLOAT_WIDTH_TEST
(
double
);
FLOAT_WIDTH_TEST
(
double
);
test
(
"Format command with
invali
d printf format: "
);
test
(
"Format command with
unhandle
d printf format
(specifier 'p' not supported)
: "
);
len
=
redisFormatCommand
(
&
cmd
,
"key:%08p %b"
,(
void
*
)
1234
,
"foo"
,(
size_t
)
3
);
len
=
redisFormatCommand
(
&
cmd
,
"key:%08p %b"
,(
void
*
)
1234
,
"foo"
,(
size_t
)
3
);
test_cond
(
len
==
-
1
);
test_cond
(
len
==
-
1
);
test
(
"Format command with invalid printf format (specifier missing): "
);
len
=
redisFormatCommand
(
&
cmd
,
"%-"
);
test_cond
(
len
==
-
1
);
const
char
*
argv
[
3
];
const
char
*
argv
[
3
];
argv
[
0
]
=
"SET"
;
argv
[
0
]
=
"SET"
;
argv
[
1
]
=
"foo
\0
xxx"
;
argv
[
1
]
=
"foo
\0
xxx"
;
...
@@ -391,6 +405,16 @@ static void test_append_formatted_commands(struct config config) {
...
@@ -391,6 +405,16 @@ static void test_append_formatted_commands(struct config config) {
disconnect
(
c
,
0
);
disconnect
(
c
,
0
);
}
}
static
void
test_tcp_options
(
struct
config
cfg
)
{
redisContext
*
c
;
c
=
do_connect
(
cfg
);
test
(
"We can enable TCP_KEEPALIVE: "
);
test_cond
(
redisEnableKeepAlive
(
c
)
==
REDIS_OK
);
disconnect
(
c
,
0
);
}
static
void
test_reply_reader
(
void
)
{
static
void
test_reply_reader
(
void
)
{
redisReader
*
reader
;
redisReader
*
reader
;
void
*
reply
,
*
root
;
void
*
reply
,
*
root
;
...
@@ -568,6 +592,19 @@ static void test_reply_reader(void) {
...
@@ -568,6 +592,19 @@ static void test_reply_reader(void) {
test_cond
(
ret
==
REDIS_ERR
&&
reply
==
NULL
);
test_cond
(
ret
==
REDIS_ERR
&&
reply
==
NULL
);
redisReaderFree
(
reader
);
redisReaderFree
(
reader
);
test
(
"Don't reset state after protocol error(not segfault): "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,(
char
*
)
"*3
\r\n
$3
\r\n
SET
\r\n
$5
\r\n
hello
\r\n
$"
,
25
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
assert
(
ret
==
REDIS_OK
);
redisReaderFeed
(
reader
,(
char
*
)
"3
\r\n
val
\r\n
"
,
8
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_ARRAY
&&
((
redisReply
*
)
reply
)
->
elements
==
3
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
/* Regression test for issue #45 on GitHub. */
/* Regression test for issue #45 on GitHub. */
test
(
"Don't do empty allocation for empty multi bulk: "
);
test
(
"Don't do empty allocation for empty multi bulk: "
);
reader
=
redisReaderCreate
();
reader
=
redisReaderCreate
();
...
@@ -637,12 +674,23 @@ static void test_reply_reader(void) {
...
@@ -637,12 +674,23 @@ static void test_reply_reader(void) {
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
redisReaderFree
(
reader
);
test
(
"
Set error when
RESP3 double
is
NaN: "
);
test
(
"
Correctly parses
RESP3 double NaN: "
);
reader
=
redisReaderCreate
();
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
",nan
\r\n
"
,
6
);
redisReaderFeed
(
reader
,
",nan
\r\n
"
,
6
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_ERR
&&
test_cond
(
ret
==
REDIS_OK
&&
strcasecmp
(
reader
->
errstr
,
"Bad double value"
)
==
0
);
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_DOUBLE
&&
isnan
(((
redisReply
*
)
reply
)
->
dval
));
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Correctly parses RESP3 double -Nan: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
",-nan
\r\n
"
,
7
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_DOUBLE
&&
isnan
(((
redisReply
*
)
reply
)
->
dval
));
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
redisReaderFree
(
reader
);
...
@@ -745,6 +793,20 @@ static void test_reply_reader(void) {
...
@@ -745,6 +793,20 @@ static void test_reply_reader(void) {
!
strcmp
(((
redisReply
*
)
reply
)
->
str
,
"3492890328409238509324850943850943825024385"
));
!
strcmp
(((
redisReply
*
)
reply
)
->
str
,
"3492890328409238509324850943850943825024385"
));
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 doubles in an array: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"*1
\r\n
,3.14159265358979323846
\r\n
"
,
31
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_ARRAY
&&
((
redisReply
*
)
reply
)
->
elements
==
1
&&
((
redisReply
*
)
reply
)
->
element
[
0
]
->
type
==
REDIS_REPLY_DOUBLE
&&
fabs
(((
redisReply
*
)
reply
)
->
element
[
0
]
->
dval
-
3
.
14159265358979323846
)
<
0
.
00000001
&&
((
redisReply
*
)
reply
)
->
element
[
0
]
->
len
==
22
&&
strcmp
(((
redisReply
*
)
reply
)
->
element
[
0
]
->
str
,
"3.14159265358979323846"
)
==
0
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
}
}
static
void
test_free_null
(
void
)
{
static
void
test_free_null
(
void
)
{
...
@@ -819,9 +881,9 @@ static void test_allocator_injection(void) {
...
@@ -819,9 +881,9 @@ static void test_allocator_injection(void) {
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
static
void
test_blocking_connection_errors
(
void
)
{
static
void
test_blocking_connection_errors
(
void
)
{
redisContext
*
c
;
struct
addrinfo
hints
=
{.
ai_family
=
AF_INET
};
struct
addrinfo
hints
=
{.
ai_family
=
AF_INET
};
struct
addrinfo
*
ai_tmp
=
NULL
;
struct
addrinfo
*
ai_tmp
=
NULL
;
redisContext
*
c
;
int
rv
=
getaddrinfo
(
HIREDIS_BAD_DOMAIN
,
"6379"
,
&
hints
,
&
ai_tmp
);
int
rv
=
getaddrinfo
(
HIREDIS_BAD_DOMAIN
,
"6379"
,
&
hints
,
&
ai_tmp
);
if
(
rv
!=
0
)
{
if
(
rv
!=
0
)
{
...
@@ -835,6 +897,7 @@ static void test_blocking_connection_errors(void) {
...
@@ -835,6 +897,7 @@ static void test_blocking_connection_errors(void) {
strcmp
(
c
->
errstr
,
"Can't resolve: "
HIREDIS_BAD_DOMAIN
)
==
0
||
strcmp
(
c
->
errstr
,
"Can't resolve: "
HIREDIS_BAD_DOMAIN
)
==
0
||
strcmp
(
c
->
errstr
,
"Name does not resolve"
)
==
0
||
strcmp
(
c
->
errstr
,
"Name does not resolve"
)
==
0
||
strcmp
(
c
->
errstr
,
"nodename nor servname provided, or not known"
)
==
0
||
strcmp
(
c
->
errstr
,
"nodename nor servname provided, or not known"
)
==
0
||
strcmp
(
c
->
errstr
,
"node name or service name not known"
)
==
0
||
strcmp
(
c
->
errstr
,
"No address associated with hostname"
)
==
0
||
strcmp
(
c
->
errstr
,
"No address associated with hostname"
)
==
0
||
strcmp
(
c
->
errstr
,
"Temporary failure in name resolution"
)
==
0
||
strcmp
(
c
->
errstr
,
"Temporary failure in name resolution"
)
==
0
||
strcmp
(
c
->
errstr
,
"hostname nor servname provided, or not known"
)
==
0
||
strcmp
(
c
->
errstr
,
"hostname nor servname provided, or not known"
)
==
0
||
...
@@ -847,12 +910,26 @@ static void test_blocking_connection_errors(void) {
...
@@ -847,12 +910,26 @@ static void test_blocking_connection_errors(void) {
}
}
#ifndef _WIN32
#ifndef _WIN32
redisOptions
opt
=
{
0
};
struct
timeval
tv
;
test
(
"Returns error when the port is not open: "
);
test
(
"Returns error when the port is not open: "
);
c
=
redisConnect
((
char
*
)
"localhost"
,
1
);
c
=
redisConnect
((
char
*
)
"localhost"
,
1
);
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Connection refused"
)
==
0
);
strcmp
(
c
->
errstr
,
"Connection refused"
)
==
0
);
redisFree
(
c
);
redisFree
(
c
);
/* Verify we don't regress from the fix in PR #1180 */
test
(
"We don't clobber connection exception with setsockopt error: "
);
tv
=
(
struct
timeval
){.
tv_sec
=
0
,
.
tv_usec
=
500000
};
opt
.
command_timeout
=
opt
.
connect_timeout
=
&
tv
;
REDIS_OPTIONS_SET_TCP
(
&
opt
,
"localhost"
,
10337
);
c
=
redisConnectWithOptions
(
&
opt
);
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Connection refused"
)
==
0
);
redisFree
(
c
);
test
(
"Returns error when the unix_sock socket path doesn't accept connections: "
);
test
(
"Returns error when the unix_sock socket path doesn't accept connections: "
);
c
=
redisConnectUnix
((
char
*
)
"/tmp/idontexist.sock"
);
c
=
redisConnectUnix
((
char
*
)
"/tmp/idontexist.sock"
);
test_cond
(
c
->
err
==
REDIS_ERR_IO
);
/* Don't care about the message... */
test_cond
(
c
->
err
==
REDIS_ERR_IO
);
/* Don't care about the message... */
...
@@ -914,11 +991,19 @@ static void test_resp3_push_handler(redisContext *c) {
...
@@ -914,11 +991,19 @@ static void test_resp3_push_handler(redisContext *c) {
old
=
redisSetPushCallback
(
c
,
push_handler
);
old
=
redisSetPushCallback
(
c
,
push_handler
);
test
(
"We can set a custom RESP3 PUSH handler: "
);
test
(
"We can set a custom RESP3 PUSH handler: "
);
reply
=
redisCommand
(
c
,
"SET key:0 val:0"
);
reply
=
redisCommand
(
c
,
"SET key:0 val:0"
);
/* We need another command because depending on the version of Redis, the
* notification may be delivered after the command's reply. */
assert
(
reply
!=
NULL
);
freeReplyObject
(
reply
);
reply
=
redisCommand
(
c
,
"PING"
);
test_cond
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_STATUS
&&
pc
.
str
==
1
);
test_cond
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_STATUS
&&
pc
.
str
==
1
);
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
test
(
"We properly handle a NIL invalidation payload: "
);
test
(
"We properly handle a NIL invalidation payload: "
);
reply
=
redisCommand
(
c
,
"FLUSHDB"
);
reply
=
redisCommand
(
c
,
"FLUSHDB"
);
assert
(
reply
!=
NULL
);
freeReplyObject
(
reply
);
reply
=
redisCommand
(
c
,
"PING"
);
test_cond
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_STATUS
&&
pc
.
nil
==
1
);
test_cond
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_STATUS
&&
pc
.
nil
==
1
);
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
...
@@ -929,6 +1014,12 @@ static void test_resp3_push_handler(redisContext *c) {
...
@@ -929,6 +1014,12 @@ static void test_resp3_push_handler(redisContext *c) {
assert
((
reply
=
redisCommand
(
c
,
"GET key:0"
))
!=
NULL
);
assert
((
reply
=
redisCommand
(
c
,
"GET key:0"
))
!=
NULL
);
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
assert
((
reply
=
redisCommand
(
c
,
"SET key:0 invalid"
))
!=
NULL
);
assert
((
reply
=
redisCommand
(
c
,
"SET key:0 invalid"
))
!=
NULL
);
/* Depending on Redis version, we may receive either push notification or
* status reply. Both cases are valid. */
if
(
reply
->
type
==
REDIS_REPLY_STATUS
)
{
freeReplyObject
(
reply
);
reply
=
redisCommand
(
c
,
"PING"
);
}
test_cond
(
reply
->
type
==
REDIS_REPLY_PUSH
);
test_cond
(
reply
->
type
==
REDIS_REPLY_PUSH
);
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
...
@@ -1089,6 +1180,13 @@ static void test_blocking_connection(struct config config) {
...
@@ -1089,6 +1180,13 @@ static void test_blocking_connection(struct config config) {
strcasecmp
(
reply
->
element
[
1
]
->
str
,
"pong"
)
==
0
);
strcasecmp
(
reply
->
element
[
1
]
->
str
,
"pong"
)
==
0
);
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
test
(
"Send command by passing argc/argv: "
);
const
char
*
argv
[
3
]
=
{
"SET"
,
"foo"
,
"bar"
};
size_t
argvlen
[
3
]
=
{
3
,
3
,
3
};
reply
=
redisCommandArgv
(
c
,
3
,
argv
,
argvlen
);
test_cond
(
reply
->
type
==
REDIS_REPLY_STATUS
);
freeReplyObject
(
reply
);
/* Make sure passing NULL to redisGetReply is safe */
/* Make sure passing NULL to redisGetReply is safe */
test
(
"Can pass NULL to redisGetReply: "
);
test
(
"Can pass NULL to redisGetReply: "
);
assert
(
redisAppendCommand
(
c
,
"PING"
)
==
REDIS_OK
);
assert
(
redisAppendCommand
(
c
,
"PING"
)
==
REDIS_OK
);
...
@@ -1143,7 +1241,13 @@ static void test_blocking_connection_timeouts(struct config config) {
...
@@ -1143,7 +1241,13 @@ static void test_blocking_connection_timeouts(struct config config) {
test
(
"Does not return a reply when the command times out: "
);
test
(
"Does not return a reply when the command times out: "
);
if
(
detect_debug_sleep
(
c
))
{
if
(
detect_debug_sleep
(
c
))
{
redisAppendFormattedCommand
(
c
,
sleep_cmd
,
strlen
(
sleep_cmd
));
redisAppendFormattedCommand
(
c
,
sleep_cmd
,
strlen
(
sleep_cmd
));
// flush connection buffer without waiting for the reply
s
=
c
->
funcs
->
write
(
c
);
s
=
c
->
funcs
->
write
(
c
);
assert
(
s
==
(
ssize_t
)
hi_sdslen
(
c
->
obuf
));
hi_sdsfree
(
c
->
obuf
);
c
->
obuf
=
hi_sdsempty
();
tv
.
tv_sec
=
0
;
tv
.
tv_sec
=
0
;
tv
.
tv_usec
=
10000
;
tv
.
tv_usec
=
10000
;
redisSetTimeout
(
c
,
tv
);
redisSetTimeout
(
c
,
tv
);
...
@@ -1156,6 +1260,9 @@ static void test_blocking_connection_timeouts(struct config config) {
...
@@ -1156,6 +1260,9 @@ static void test_blocking_connection_timeouts(struct config config) {
strcmp
(
c
->
errstr
,
"recv timeout"
)
==
0
);
strcmp
(
c
->
errstr
,
"recv timeout"
)
==
0
);
#endif
#endif
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
// wait for the DEBUG SLEEP to complete so that Redis server is unblocked for the following tests
millisleep
(
3000
);
}
else
{
}
else
{
test_skipped
();
test_skipped
();
}
}
...
@@ -1226,22 +1333,34 @@ static void test_blocking_io_errors(struct config config) {
...
@@ -1226,22 +1333,34 @@ static void test_blocking_io_errors(struct config config) {
static
void
test_invalid_timeout_errors
(
struct
config
config
)
{
static
void
test_invalid_timeout_errors
(
struct
config
config
)
{
redisContext
*
c
;
redisContext
*
c
;
test
(
"Set error when an invalid timeout usec value is
given to redisConnectWithTimeou
t: "
);
test
(
"Set error when an invalid timeout usec value is
used during connec
t: "
);
config
.
tcp
.
timeout
.
tv_sec
=
0
;
config
.
connect_
timeout
.
tv_sec
=
0
;
config
.
tcp
.
timeout
.
tv_usec
=
10000001
;
config
.
connect_
timeout
.
tv_usec
=
10000001
;
c
=
redisConnectWithTimeout
(
config
.
tcp
.
host
,
config
.
tcp
.
port
,
config
.
tcp
.
timeout
);
if
(
config
.
type
==
CONN_TCP
||
config
.
type
==
CONN_SSL
)
{
c
=
redisConnectWithTimeout
(
config
.
tcp
.
host
,
config
.
tcp
.
port
,
config
.
connect_timeout
);
}
else
if
(
config
.
type
==
CONN_UNIX
)
{
c
=
redisConnectUnixWithTimeout
(
config
.
unix_sock
.
path
,
config
.
connect_timeout
);
}
else
{
assert
(
NULL
);
}
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Invalid timeout specified"
)
==
0
);
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Invalid timeout specified"
)
==
0
);
redisFree
(
c
);
redisFree
(
c
);
test
(
"Set error when an invalid timeout sec value is
given to redisConnectWithTimeou
t: "
);
test
(
"Set error when an invalid timeout sec value is
used during connec
t: "
);
config
.
tcp
.
timeout
.
tv_sec
=
(((
LONG_MAX
)
-
999
)
/
1000
)
+
1
;
config
.
connect_
timeout
.
tv_sec
=
(((
LONG_MAX
)
-
999
)
/
1000
)
+
1
;
config
.
tcp
.
timeout
.
tv_usec
=
0
;
config
.
connect_
timeout
.
tv_usec
=
0
;
c
=
redisConnectWithTimeout
(
config
.
tcp
.
host
,
config
.
tcp
.
port
,
config
.
tcp
.
timeout
);
if
(
config
.
type
==
CONN_TCP
||
config
.
type
==
CONN_SSL
)
{
c
=
redisConnectWithTimeout
(
config
.
tcp
.
host
,
config
.
tcp
.
port
,
config
.
connect_timeout
);
}
else
if
(
config
.
type
==
CONN_UNIX
)
{
c
=
redisConnectUnixWithTimeout
(
config
.
unix_sock
.
path
,
config
.
connect_timeout
);
}
else
{
assert
(
NULL
);
}
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Invalid timeout specified"
)
==
0
);
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Invalid timeout specified"
)
==
0
);
redisFree
(
c
);
redisFree
(
c
);
...
@@ -1729,10 +1848,14 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
...
@@ -1729,10 +1848,14 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
strcmp
(
reply
->
element
[
2
]
->
str
,
"Hello!"
)
==
0
);
strcmp
(
reply
->
element
[
2
]
->
str
,
"Hello!"
)
==
0
);
state
->
checkpoint
++
;
state
->
checkpoint
++
;
/* Unsubscribe to channels, including
a
channel X which we don't subscribe to */
/* Unsubscribe to channels, including channel X
& Z
which we don't subscribe to */
redisAsyncCommand
(
ac
,
unexpected_cb
,
redisAsyncCommand
(
ac
,
unexpected_cb
,
(
void
*
)
"unsubscribe should not call unexpected_cb()"
,
(
void
*
)
"unsubscribe should not call unexpected_cb()"
,
"unsubscribe B X A"
);
"unsubscribe B X A A Z"
);
/* Unsubscribe to patterns, none which we subscribe to */
redisAsyncCommand
(
ac
,
unexpected_cb
,
(
void
*
)
"punsubscribe should not call unexpected_cb()"
,
"punsubscribe"
);
/* Send a regular command after unsubscribing, then disconnect */
/* Send a regular command after unsubscribing, then disconnect */
state
->
disconnect
=
1
;
state
->
disconnect
=
1
;
redisAsyncCommand
(
ac
,
integer_cb
,
state
,
"LPUSH mylist foo"
);
redisAsyncCommand
(
ac
,
integer_cb
,
state
,
"LPUSH mylist foo"
);
...
@@ -1749,6 +1872,7 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
...
@@ -1749,6 +1872,7 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
void
subscribe_channel_b_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
void
subscribe_channel_b_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
TestState
*
state
=
privdata
;
(
void
)
ac
;
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_ARRAY
&&
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_ARRAY
&&
reply
->
elements
==
3
);
reply
->
elements
==
3
);
...
@@ -1767,8 +1891,10 @@ void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
...
@@ -1767,8 +1891,10 @@ void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
/* Test handling of multiple channels
/* Test handling of multiple channels
* - subscribe to channel A and B
* - subscribe to channel A and B
* - a published message on A triggers an unsubscribe of channel B, X and A
* - a published message on A triggers an unsubscribe of channel B, X, A and Z
* where channel X is not subscribed to.
* where channel X and Z are not subscribed to.
* - the published message also triggers an unsubscribe to patterns. Since no
* pattern is subscribed to the responded pattern element type is NIL.
* - a command sent after unsubscribe triggers a disconnect */
* - a command sent after unsubscribe triggers a disconnect */
static
void
test_pubsub_multiple_channels
(
struct
config
config
)
{
static
void
test_pubsub_multiple_channels
(
struct
config
config
)
{
test
(
"Subscribe to multiple channels: "
);
test
(
"Subscribe to multiple channels: "
);
...
@@ -1881,6 +2007,250 @@ static void test_monitor(struct config config) {
...
@@ -1881,6 +2007,250 @@ static void test_monitor(struct config config) {
}
}
#endif
/* HIREDIS_TEST_ASYNC */
#endif
/* HIREDIS_TEST_ASYNC */
/* tests for async api using polling adapter, requires no extra libraries*/
/* enum for the test cases, the callbacks have different logic based on them */
typedef
enum
astest_no
{
ASTEST_CONNECT
=
0
,
ASTEST_CONN_TIMEOUT
,
ASTEST_PINGPONG
,
ASTEST_PINGPONG_TIMEOUT
,
ASTEST_ISSUE_931
,
ASTEST_ISSUE_931_PING
}
astest_no
;
/* a static context for the async tests */
struct
_astest
{
redisAsyncContext
*
ac
;
astest_no
testno
;
int
counter
;
int
connects
;
int
connect_status
;
int
disconnects
;
int
pongs
;
int
disconnect_status
;
int
connected
;
int
err
;
char
errstr
[
256
];
};
static
struct
_astest
astest
;
/* async callbacks */
static
void
asCleanup
(
void
*
data
)
{
struct
_astest
*
t
=
(
struct
_astest
*
)
data
;
t
->
ac
=
NULL
;
}
static
void
commandCallback
(
struct
redisAsyncContext
*
ac
,
void
*
_reply
,
void
*
_privdata
);
static
void
connectCallback
(
redisAsyncContext
*
c
,
int
status
)
{
struct
_astest
*
t
=
(
struct
_astest
*
)
c
->
data
;
assert
(
t
==
&
astest
);
assert
(
t
->
connects
==
0
);
t
->
err
=
c
->
err
;
strcpy
(
t
->
errstr
,
c
->
errstr
);
t
->
connects
++
;
t
->
connect_status
=
status
;
t
->
connected
=
status
==
REDIS_OK
?
1
:
-
1
;
if
(
t
->
testno
==
ASTEST_ISSUE_931
)
{
/* disconnect again */
redisAsyncDisconnect
(
c
);
}
else
if
(
t
->
testno
==
ASTEST_ISSUE_931_PING
)
{
redisAsyncCommand
(
c
,
commandCallback
,
NULL
,
"PING"
);
}
}
static
void
disconnectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
assert
(
c
->
data
==
(
void
*
)
&
astest
);
assert
(
astest
.
disconnects
==
0
);
astest
.
err
=
c
->
err
;
strcpy
(
astest
.
errstr
,
c
->
errstr
);
astest
.
disconnects
++
;
astest
.
disconnect_status
=
status
;
astest
.
connected
=
0
;
}
static
void
commandCallback
(
struct
redisAsyncContext
*
ac
,
void
*
_reply
,
void
*
_privdata
)
{
redisReply
*
reply
=
(
redisReply
*
)
_reply
;
struct
_astest
*
t
=
(
struct
_astest
*
)
ac
->
data
;
assert
(
t
==
&
astest
);
(
void
)
_privdata
;
t
->
err
=
ac
->
err
;
strcpy
(
t
->
errstr
,
ac
->
errstr
);
t
->
counter
++
;
if
(
t
->
testno
==
ASTEST_PINGPONG
||
t
->
testno
==
ASTEST_ISSUE_931_PING
)
{
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_STATUS
&&
strcmp
(
reply
->
str
,
"PONG"
)
==
0
);
t
->
pongs
++
;
redisAsyncFree
(
ac
);
}
if
(
t
->
testno
==
ASTEST_PINGPONG_TIMEOUT
)
{
/* two ping pongs */
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_STATUS
&&
strcmp
(
reply
->
str
,
"PONG"
)
==
0
);
t
->
pongs
++
;
if
(
t
->
counter
==
1
)
{
int
status
=
redisAsyncCommand
(
ac
,
commandCallback
,
NULL
,
"PING"
);
assert
(
status
==
REDIS_OK
);
}
else
{
redisAsyncFree
(
ac
);
}
}
}
static
redisAsyncContext
*
do_aconnect
(
struct
config
config
,
astest_no
testno
)
{
redisOptions
options
=
{
0
};
memset
(
&
astest
,
0
,
sizeof
(
astest
));
astest
.
testno
=
testno
;
astest
.
connect_status
=
astest
.
disconnect_status
=
-
2
;
if
(
config
.
type
==
CONN_TCP
)
{
options
.
type
=
REDIS_CONN_TCP
;
options
.
connect_timeout
=
&
config
.
connect_timeout
;
REDIS_OPTIONS_SET_TCP
(
&
options
,
config
.
tcp
.
host
,
config
.
tcp
.
port
);
}
else
if
(
config
.
type
==
CONN_SSL
)
{
options
.
type
=
REDIS_CONN_TCP
;
options
.
connect_timeout
=
&
config
.
connect_timeout
;
REDIS_OPTIONS_SET_TCP
(
&
options
,
config
.
ssl
.
host
,
config
.
ssl
.
port
);
}
else
if
(
config
.
type
==
CONN_UNIX
)
{
options
.
type
=
REDIS_CONN_UNIX
;
options
.
endpoint
.
unix_socket
=
config
.
unix_sock
.
path
;
}
else
if
(
config
.
type
==
CONN_FD
)
{
options
.
type
=
REDIS_CONN_USERFD
;
/* Create a dummy connection just to get an fd to inherit */
redisContext
*
dummy_ctx
=
redisConnectUnix
(
config
.
unix_sock
.
path
);
if
(
dummy_ctx
)
{
redisFD
fd
=
disconnect
(
dummy_ctx
,
1
);
printf
(
"Connecting to inherited fd %d
\n
"
,
(
int
)
fd
);
options
.
endpoint
.
fd
=
fd
;
}
}
redisAsyncContext
*
c
=
redisAsyncConnectWithOptions
(
&
options
);
assert
(
c
);
astest
.
ac
=
c
;
c
->
data
=
&
astest
;
c
->
dataCleanup
=
asCleanup
;
redisPollAttach
(
c
);
redisAsyncSetConnectCallbackNC
(
c
,
connectCallback
);
redisAsyncSetDisconnectCallback
(
c
,
disconnectCallback
);
return
c
;
}
static
void
as_printerr
(
void
)
{
printf
(
"Async err %d : %s
\n
"
,
astest
.
err
,
astest
.
errstr
);
}
#define ASASSERT(e) do { \
if (!(e)) \
as_printerr(); \
assert(e); \
} while (0);
static
void
test_async_polling
(
struct
config
config
)
{
int
status
;
redisAsyncContext
*
c
;
struct
config
defaultconfig
=
config
;
test
(
"Async connect: "
);
c
=
do_aconnect
(
config
,
ASTEST_CONNECT
);
assert
(
c
);
while
(
astest
.
connected
==
0
)
redisPollTick
(
c
,
0
.
1
);
assert
(
astest
.
connects
==
1
);
ASASSERT
(
astest
.
connect_status
==
REDIS_OK
);
assert
(
astest
.
disconnects
==
0
);
test_cond
(
astest
.
connected
==
1
);
test
(
"Async free after connect: "
);
assert
(
astest
.
ac
!=
NULL
);
redisAsyncFree
(
c
);
assert
(
astest
.
disconnects
==
1
);
assert
(
astest
.
ac
==
NULL
);
test_cond
(
astest
.
disconnect_status
==
REDIS_OK
);
if
(
config
.
type
==
CONN_TCP
||
config
.
type
==
CONN_SSL
)
{
/* timeout can only be simulated with network */
test
(
"Async connect timeout: "
);
config
.
tcp
.
host
=
"192.168.254.254"
;
/* blackhole ip */
config
.
connect_timeout
.
tv_usec
=
100000
;
c
=
do_aconnect
(
config
,
ASTEST_CONN_TIMEOUT
);
assert
(
c
);
assert
(
c
->
err
==
0
);
while
(
astest
.
connected
==
0
)
redisPollTick
(
c
,
0
.
1
);
assert
(
astest
.
connected
==
-
1
);
/*
* freeing should not be done, clearing should have happened.
*redisAsyncFree(c);
*/
assert
(
astest
.
ac
==
NULL
);
test_cond
(
astest
.
connect_status
==
REDIS_ERR
);
config
=
defaultconfig
;
}
/* Test a ping/pong after connection */
test
(
"Async PING/PONG: "
);
c
=
do_aconnect
(
config
,
ASTEST_PINGPONG
);
while
(
astest
.
connected
==
0
)
redisPollTick
(
c
,
0
.
1
);
status
=
redisAsyncCommand
(
c
,
commandCallback
,
NULL
,
"PING"
);
assert
(
status
==
REDIS_OK
);
while
(
astest
.
ac
)
redisPollTick
(
c
,
0
.
1
);
test_cond
(
astest
.
pongs
==
1
);
/* Test a ping/pong after connection that didn't time out.
* see https://github.com/redis/hiredis/issues/945
*/
if
(
config
.
type
==
CONN_TCP
||
config
.
type
==
CONN_SSL
)
{
test
(
"Async PING/PONG after connect timeout: "
);
config
.
connect_timeout
.
tv_usec
=
10000
;
/* 10ms */
c
=
do_aconnect
(
config
,
ASTEST_PINGPONG_TIMEOUT
);
while
(
astest
.
connected
==
0
)
redisPollTick
(
c
,
0
.
1
);
/* sleep 0.1 s, allowing old timeout to arrive */
millisleep
(
10
);
status
=
redisAsyncCommand
(
c
,
commandCallback
,
NULL
,
"PING"
);
assert
(
status
==
REDIS_OK
);
while
(
astest
.
ac
)
redisPollTick
(
c
,
0
.
1
);
test_cond
(
astest
.
pongs
==
2
);
config
=
defaultconfig
;
}
/* Test disconnect from an on_connect callback
* see https://github.com/redis/hiredis/issues/931
*/
test
(
"Disconnect from onConnected callback (Issue #931): "
);
c
=
do_aconnect
(
config
,
ASTEST_ISSUE_931
);
while
(
astest
.
disconnects
==
0
)
redisPollTick
(
c
,
0
.
1
);
assert
(
astest
.
connected
==
0
);
assert
(
astest
.
connects
==
1
);
test_cond
(
astest
.
disconnects
==
1
);
/* Test ping/pong from an on_connect callback
* see https://github.com/redis/hiredis/issues/931
*/
test
(
"Ping/Pong from onConnected callback (Issue #931): "
);
c
=
do_aconnect
(
config
,
ASTEST_ISSUE_931_PING
);
/* connect callback issues ping, reponse callback destroys context */
while
(
astest
.
ac
)
redisPollTick
(
c
,
0
.
1
);
assert
(
astest
.
connected
==
0
);
assert
(
astest
.
connects
==
1
);
assert
(
astest
.
disconnects
==
1
);
test_cond
(
astest
.
pongs
==
1
);
}
/* End of Async polling_adapter driven tests */
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
struct
config
cfg
=
{
struct
config
cfg
=
{
.
tcp
=
{
.
tcp
=
{
...
@@ -1963,6 +2333,7 @@ int main(int argc, char **argv) {
...
@@ -1963,6 +2333,7 @@ int main(int argc, char **argv) {
test_blocking_io_errors
(
cfg
);
test_blocking_io_errors
(
cfg
);
test_invalid_timeout_errors
(
cfg
);
test_invalid_timeout_errors
(
cfg
);
test_append_formatted_commands
(
cfg
);
test_append_formatted_commands
(
cfg
);
test_tcp_options
(
cfg
);
if
(
throughput
)
test_throughput
(
cfg
);
if
(
throughput
)
test_throughput
(
cfg
);
printf
(
"
\n
Testing against Unix socket connection (%s): "
,
cfg
.
unix_sock
.
path
);
printf
(
"
\n
Testing against Unix socket connection (%s): "
,
cfg
.
unix_sock
.
path
);
...
@@ -1972,6 +2343,7 @@ int main(int argc, char **argv) {
...
@@ -1972,6 +2343,7 @@ int main(int argc, char **argv) {
test_blocking_connection
(
cfg
);
test_blocking_connection
(
cfg
);
test_blocking_connection_timeouts
(
cfg
);
test_blocking_connection_timeouts
(
cfg
);
test_blocking_io_errors
(
cfg
);
test_blocking_io_errors
(
cfg
);
test_invalid_timeout_errors
(
cfg
);
if
(
throughput
)
test_throughput
(
cfg
);
if
(
throughput
)
test_throughput
(
cfg
);
}
else
{
}
else
{
test_skipped
();
test_skipped
();
...
@@ -2000,6 +2372,7 @@ int main(int argc, char **argv) {
...
@@ -2000,6 +2372,7 @@ int main(int argc, char **argv) {
#endif
#endif
#ifdef HIREDIS_TEST_ASYNC
#ifdef HIREDIS_TEST_ASYNC
cfg
.
type
=
CONN_TCP
;
printf
(
"
\n
Testing asynchronous API against TCP connection (%s:%d):
\n
"
,
cfg
.
tcp
.
host
,
cfg
.
tcp
.
port
);
printf
(
"
\n
Testing asynchronous API against TCP connection (%s:%d):
\n
"
,
cfg
.
tcp
.
host
,
cfg
.
tcp
.
port
);
cfg
.
type
=
CONN_TCP
;
cfg
.
type
=
CONN_TCP
;
...
@@ -2017,6 +2390,15 @@ int main(int argc, char **argv) {
...
@@ -2017,6 +2390,15 @@ int main(int argc, char **argv) {
}
}
#endif
/* HIREDIS_TEST_ASYNC */
#endif
/* HIREDIS_TEST_ASYNC */
cfg
.
type
=
CONN_TCP
;
printf
(
"
\n
Testing asynchronous API using polling_adapter TCP (%s:%d):
\n
"
,
cfg
.
tcp
.
host
,
cfg
.
tcp
.
port
);
test_async_polling
(
cfg
);
if
(
test_unix_socket
)
{
cfg
.
type
=
CONN_UNIX
;
printf
(
"
\n
Testing asynchronous API using polling_adapter UNIX (%s):
\n
"
,
cfg
.
unix_sock
.
path
);
test_async_polling
(
cfg
);
}
if
(
test_inherit_fd
)
{
if
(
test_inherit_fd
)
{
printf
(
"
\n
Testing against inherited fd (%s): "
,
cfg
.
unix_sock
.
path
);
printf
(
"
\n
Testing against inherited fd (%s): "
,
cfg
.
unix_sock
.
path
);
if
(
test_unix_socket
)
{
if
(
test_unix_socket
)
{
...
...
Prev
1
2
3
Next
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