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
3f073b1d
Unverified
Commit
3f073b1d
authored
Aug 09, 2020
by
Yossi Gottlieb
Committed by
GitHub
Aug 09, 2020
Browse files
Merge pull request #7609 from michael-grunder/redis-cli-resp3-push
Add redis-cli RESP3 Push support
parents
3f494cc4
81879bc1
Changes
47
Expand all
Show whitespace changes
Inline
Side-by-side
deps/hiredis/sdsalloc.h
View file @
3f073b1d
...
...
@@ -37,6 +37,8 @@
* the include of your alternate allocator if needed (not needed in order
* to use the default libc allocator). */
#define s_malloc malloc
#define s_realloc realloc
#define s_free free
#include "alloc.h"
#define s_malloc hi_malloc
#define s_realloc hi_realloc
#define s_free hi_free
deps/hiredis/sockcompat.c
View file @
3f073b1d
...
...
@@ -212,7 +212,7 @@ int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, sockle
int
win32_setsockopt
(
SOCKET
sockfd
,
int
level
,
int
optname
,
const
void
*
optval
,
socklen_t
optlen
)
{
int
ret
=
0
;
if
((
level
==
SOL_SOCKET
)
&&
((
optname
==
SO_RCVTIMEO
)
||
(
optname
==
SO_SNDTIMEO
)))
{
struct
timeval
*
tv
=
optval
;
const
struct
timeval
*
tv
=
optval
;
DWORD
timeout
=
tv
->
tv_sec
*
1000
+
tv
->
tv_usec
/
1000
;
ret
=
setsockopt
(
sockfd
,
level
,
optname
,
(
const
char
*
)
&
timeout
,
sizeof
(
DWORD
));
}
else
{
...
...
deps/hiredis/sockcompat.h
View file @
3f073b1d
...
...
@@ -49,9 +49,10 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stddef.h>
#include <errno.h>
#ifdef _MSC_VER
typedef
signed
long
ssize_t
;
typedef
long
long
ssize_t
;
#endif
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
...
...
deps/hiredis/ssl.c
View file @
3f073b1d
...
...
@@ -34,25 +34,33 @@
#include "async.h"
#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "win32.h"
#include "async_private.h"
#include "hiredis_ssl.h"
void
__redisSetError
(
redisContext
*
c
,
int
type
,
const
char
*
str
);
/* The SSL context is attached to SSL/TLS connections as a privdata. */
typedef
struct
redisSSLContext
{
/**
* OpenSSL SSL_CTX; It is optional and will not be set when using
* user-supplied SSL.
*/
struct
redisSSLContext
{
/* Associated OpenSSL SSL_CTX as created by redisCreateSSLContext() */
SSL_CTX
*
ssl_ctx
;
/* Requested SNI, or NULL */
char
*
server_name
;
};
/* The SSL connection context is attached to SSL/TLS connections as a privdata. */
typedef
struct
redisSSL
{
/**
* OpenSSL SSL object.
*/
...
...
@@ -72,43 +80,11 @@ typedef struct redisSSLContext {
* should resume whenever a read takes place, if possible
*/
int
pendingWrite
;
}
redisSSL
Context
;
}
redisSSL
;
/* Forward declaration */
redisContextFuncs
redisContextSSLFuncs
;
#ifdef HIREDIS_SSL_TRACE
/**
* Callback used for debugging
*/
static
void
sslLogCallback
(
const
SSL
*
ssl
,
int
where
,
int
ret
)
{
const
char
*
retstr
=
""
;
int
should_log
=
1
;
/* Ignore low-level SSL stuff */
if
(
where
&
SSL_CB_ALERT
)
{
should_log
=
1
;
}
if
(
where
==
SSL_CB_HANDSHAKE_START
||
where
==
SSL_CB_HANDSHAKE_DONE
)
{
should_log
=
1
;
}
if
((
where
&
SSL_CB_EXIT
)
&&
ret
==
0
)
{
should_log
=
1
;
}
if
(
!
should_log
)
{
return
;
}
retstr
=
SSL_alert_type_string
(
ret
);
printf
(
"ST(0x%x). %s. R(0x%x)%s
\n
"
,
where
,
SSL_state_string_long
(
ssl
),
ret
,
retstr
);
if
(
where
==
SSL_CB_HANDSHAKE_DONE
)
{
printf
(
"Using SSL version %s. Cipher=%s
\n
"
,
SSL_get_version
(
ssl
),
SSL_get_cipher_name
(
ssl
));
}
}
#endif
/**
* OpenSSL global initialization and locking handling callbacks.
* Note that this is only required for OpenSSL < 1.1.0.
...
...
@@ -119,6 +95,18 @@ static void sslLogCallback(const SSL *ssl, int where, int ret) {
#endif
#ifdef HIREDIS_USE_CRYPTO_LOCKS
#ifdef _WIN32
typedef
CRITICAL_SECTION
sslLockType
;
static
void
sslLockInit
(
sslLockType
*
l
)
{
InitializeCriticalSection
(
l
);
}
static
void
sslLockAcquire
(
sslLockType
*
l
)
{
EnterCriticalSection
(
l
);
}
static
void
sslLockRelease
(
sslLockType
*
l
)
{
LeaveCriticalSection
(
l
);
}
#else
typedef
pthread_mutex_t
sslLockType
;
static
void
sslLockInit
(
sslLockType
*
l
)
{
pthread_mutex_init
(
l
,
NULL
);
...
...
@@ -129,7 +117,9 @@ static void sslLockAcquire(sslLockType *l) {
static
void
sslLockRelease
(
sslLockType
*
l
)
{
pthread_mutex_unlock
(
l
);
}
static
pthread_mutex_t
*
ossl_locks
;
#endif
static
sslLockType
*
ossl_locks
;
static
void
opensslDoLock
(
int
mode
,
int
lkid
,
const
char
*
f
,
int
line
)
{
sslLockType
*
l
=
ossl_locks
+
lkid
;
...
...
@@ -144,36 +134,151 @@ static void opensslDoLock(int mode, int lkid, const char *f, int line) {
(
void
)
line
;
}
static
void
initOpensslLocks
(
void
)
{
static
int
initOpensslLocks
(
void
)
{
unsigned
ii
,
nlocks
;
if
(
CRYPTO_get_locking_callback
()
!=
NULL
)
{
/* Someone already set the callback before us. Don't destroy it! */
return
;
return
REDIS_OK
;
}
nlocks
=
CRYPTO_num_locks
();
ossl_locks
=
malloc
(
sizeof
(
*
ossl_locks
)
*
nlocks
);
ossl_locks
=
hi_malloc
(
sizeof
(
*
ossl_locks
)
*
nlocks
);
if
(
ossl_locks
==
NULL
)
return
REDIS_ERR
;
for
(
ii
=
0
;
ii
<
nlocks
;
ii
++
)
{
sslLockInit
(
ossl_locks
+
ii
);
}
CRYPTO_set_locking_callback
(
opensslDoLock
);
return
REDIS_OK
;
}
#endif
/* HIREDIS_USE_CRYPTO_LOCKS */
int
redisInitOpenSSL
(
void
)
{
SSL_library_init
();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
initOpensslLocks
();
#endif
return
REDIS_OK
;
}
/**
* redisSSLContext helper context destruction.
*/
const
char
*
redisSSLContextGetError
(
redisSSLContextError
error
)
{
switch
(
error
)
{
case
REDIS_SSL_CTX_NONE
:
return
"No Error"
;
case
REDIS_SSL_CTX_CREATE_FAILED
:
return
"Failed to create OpenSSL SSL_CTX"
;
case
REDIS_SSL_CTX_CERT_KEY_REQUIRED
:
return
"Client cert and key must both be specified or skipped"
;
case
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
:
return
"Failed to load CA Certificate or CA Path"
;
case
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
:
return
"Failed to load client certificate"
;
case
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
:
return
"Failed to load private key"
;
default:
return
"Unknown error code"
;
}
}
void
redisFreeSSLContext
(
redisSSLContext
*
ctx
)
{
if
(
!
ctx
)
return
;
if
(
ctx
->
server_name
)
{
hi_free
(
ctx
->
server_name
);
ctx
->
server_name
=
NULL
;
}
if
(
ctx
->
ssl_ctx
)
{
SSL_CTX_free
(
ctx
->
ssl_ctx
);
ctx
->
ssl_ctx
=
NULL
;
}
hi_free
(
ctx
);
}
/**
* redisSSLContext helper context initialization.
*/
redisSSLContext
*
redisCreateSSLContext
(
const
char
*
cacert_filename
,
const
char
*
capath
,
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
server_name
,
redisSSLContextError
*
error
)
{
redisSSLContext
*
ctx
=
hi_calloc
(
1
,
sizeof
(
redisSSLContext
));
if
(
ctx
==
NULL
)
goto
error
;
ctx
->
ssl_ctx
=
SSL_CTX_new
(
SSLv23_client_method
());
if
(
!
ctx
->
ssl_ctx
)
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CREATE_FAILED
;
goto
error
;
}
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
);
if
((
cert_filename
!=
NULL
&&
private_key_filename
==
NULL
)
||
(
private_key_filename
!=
NULL
&&
cert_filename
==
NULL
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CERT_KEY_REQUIRED
;
goto
error
;
}
if
(
capath
||
cacert_filename
)
{
if
(
!
SSL_CTX_load_verify_locations
(
ctx
->
ssl_ctx
,
cacert_filename
,
capath
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
;
goto
error
;
}
}
if
(
cert_filename
)
{
if
(
!
SSL_CTX_use_certificate_chain_file
(
ctx
->
ssl_ctx
,
cert_filename
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
;
goto
error
;
}
if
(
!
SSL_CTX_use_PrivateKey_file
(
ctx
->
ssl_ctx
,
private_key_filename
,
SSL_FILETYPE_PEM
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
;
goto
error
;
}
}
if
(
server_name
)
ctx
->
server_name
=
hi_strdup
(
server_name
);
return
ctx
;
error:
redisFreeSSLContext
(
ctx
);
return
NULL
;
}
/**
* SSL Connection initialization.
*/
static
int
redisSSLConnect
(
redisContext
*
c
,
SSL_CTX
*
ssl_ctx
,
SSL
*
ssl
)
{
if
(
c
->
privdata
)
{
static
int
redisSSLConnect
(
redisContext
*
c
,
SSL
*
ssl
)
{
if
(
c
->
privctx
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"redisContext was already associated"
);
return
REDIS_ERR
;
}
c
->
privdata
=
calloc
(
1
,
sizeof
(
redisSSLContext
));
c
->
funcs
=
&
redisContextSSLFuncs
;
redisSSLContext
*
rssl
=
c
->
privdata
;
redisSSL
*
rssl
=
hi_calloc
(
1
,
sizeof
(
redisSSL
));
if
(
rssl
==
NULL
)
{
__redisSetError
(
c
,
REDIS_ERR_OOM
,
"Out of memory"
);
return
REDIS_ERR
;
}
rssl
->
ssl_ctx
=
ssl_ctx
;
c
->
funcs
=
&
redisContextSSLFuncs
;
rssl
->
ssl
=
ssl
;
SSL_set_mode
(
rssl
->
ssl
,
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
);
...
...
@@ -183,12 +288,14 @@ static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
ERR_clear_error
();
int
rv
=
SSL_connect
(
rssl
->
ssl
);
if
(
rv
==
1
)
{
c
->
privctx
=
rssl
;
return
REDIS_OK
;
}
rv
=
SSL_get_error
(
rssl
->
ssl
,
rv
);
if
(((
c
->
flags
&
REDIS_BLOCK
)
==
0
)
&&
(
rv
==
SSL_ERROR_WANT_READ
||
rv
==
SSL_ERROR_WANT_WRITE
))
{
c
->
privctx
=
rssl
;
return
REDIS_OK
;
}
...
...
@@ -203,83 +310,58 @@ static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
}
__redisSetError
(
c
,
REDIS_ERR_IO
,
err
);
}
hi_free
(
rssl
);
return
REDIS_ERR
;
}
/**
* A wrapper around redisSSLConnect() for users who manage their own context and
* create their own SSL object.
*/
int
redisInitiateSSL
(
redisContext
*
c
,
SSL
*
ssl
)
{
return
redisSSLConnect
(
c
,
NULL
,
ssl
);
return
redisSSLConnect
(
c
,
ssl
);
}
int
redisSecureConnection
(
redisContext
*
c
,
const
char
*
capath
,
const
char
*
certpath
,
const
char
*
keypath
,
const
char
*
servername
)
{
SSL_CTX
*
ssl_ctx
=
NULL
;
SSL
*
ssl
=
NULL
;
/* Initialize global OpenSSL stuff */
static
int
isInit
=
0
;
if
(
!
isInit
)
{
isInit
=
1
;
SSL_library_init
();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
initOpensslLocks
();
#endif
}
ssl_ctx
=
SSL_CTX_new
(
SSLv23_client_method
());
if
(
!
ssl_ctx
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Failed to create SSL_CTX"
);
goto
error
;
}
/**
* A wrapper around redisSSLConnect() for users who use redisSSLContext and don't
* manage their own SSL objects.
*/
#ifdef HIREDIS_SSL_TRACE
SSL_CTX_set_info_callback
(
ssl_ctx
,
sslLogCallback
);
#endif
SSL_CTX_set_options
(
ssl_ctx
,
SSL_OP_NO_SSLv2
|
SSL_OP_NO_SSLv3
);
SSL_CTX_set_verify
(
ssl_ctx
,
SSL_VERIFY_PEER
,
NULL
);
if
((
certpath
!=
NULL
&&
keypath
==
NULL
)
||
(
keypath
!=
NULL
&&
certpath
==
NULL
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"certpath and keypath must be specified together"
);
goto
error
;
}
int
redisInitiateSSLWithContext
(
redisContext
*
c
,
redisSSLContext
*
redis_ssl_ctx
)
{
if
(
!
c
||
!
redis_ssl_ctx
)
return
REDIS_ERR
;
if
(
capath
)
{
if
(
!
SSL_CTX_load_verify_locations
(
ssl_ctx
,
capath
,
NULL
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Invalid CA certificate"
);
goto
error
;
}
}
if
(
certpath
)
{
if
(
!
SSL_CTX_use_certificate_chain_file
(
ssl_ctx
,
certpath
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Invalid client certificate"
);
goto
error
;
}
if
(
!
SSL_CTX_use_PrivateKey_file
(
ssl_ctx
,
keypath
,
SSL_FILETYPE_PEM
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Invalid client key"
);
goto
error
;
}
}
/* We want to verify that redisSSLConnect() won't fail on this, as it will
* not own the SSL object in that case and we'll end up leaking.
*/
if
(
c
->
privctx
)
return
REDIS_ERR
;
ssl
=
SSL_new
(
ssl_ctx
);
SSL
*
ssl
=
SSL_new
(
redis_ssl_ctx
->
ssl_ctx
);
if
(
!
ssl
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Couldn't create new SSL instance"
);
goto
error
;
}
if
(
servername
)
{
if
(
!
SSL_set_tlsext_host_name
(
ssl
,
servername
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Couldn't set server name indication"
);
if
(
redis_ssl_ctx
->
server_name
)
{
if
(
!
SSL_set_tlsext_host_name
(
ssl
,
redis_ssl_ctx
->
server_name
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Failed to set server_name/SNI"
);
goto
error
;
}
}
return
redisSSLConnect
(
c
,
ssl_ctx
,
ssl
);
return
redisSSLConnect
(
c
,
ssl
);
error:
if
(
ssl
)
SSL_free
(
ssl
);
if
(
ssl_ctx
)
SSL_
CTX_
free
(
ssl
_ctx
);
if
(
ssl
)
SSL_free
(
ssl
);
return
REDIS_ERR
;
}
static
int
maybeCheckWant
(
redisSSL
Context
*
rssl
,
int
rv
)
{
static
int
maybeCheckWant
(
redisSSL
*
rssl
,
int
rv
)
{
/**
* If the error is WANT_READ or WANT_WRITE, the appropriate flags are set
* and true is returned. False is returned otherwise
...
...
@@ -299,23 +381,19 @@ static int maybeCheckWant(redisSSLContext *rssl, int rv) {
* Implementation of redisContextFuncs for SSL connections.
*/
static
void
redisSSLFree
Context
(
void
*
priv
data
){
redisSSL
Context
*
rsc
=
priv
data
;
static
void
redisSSLFree
(
void
*
priv
ctx
){
redisSSL
*
rsc
=
priv
ctx
;
if
(
!
rsc
)
return
;
if
(
rsc
->
ssl
)
{
SSL_free
(
rsc
->
ssl
);
rsc
->
ssl
=
NULL
;
}
if
(
rsc
->
ssl_ctx
)
{
SSL_CTX_free
(
rsc
->
ssl_ctx
);
rsc
->
ssl_ctx
=
NULL
;
}
free
(
rsc
);
hi_free
(
rsc
);
}
static
in
t
redisSSLRead
(
redisContext
*
c
,
char
*
buf
,
size_t
bufcap
)
{
redisSSL
Context
*
rssl
=
c
->
priv
data
;
static
ssize_
t
redisSSLRead
(
redisContext
*
c
,
char
*
buf
,
size_t
bufcap
)
{
redisSSL
*
rssl
=
c
->
priv
ctx
;
int
nread
=
SSL_read
(
rssl
->
ssl
,
buf
,
bufcap
);
if
(
nread
>
0
)
{
...
...
@@ -356,8 +434,8 @@ static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
}
}
static
in
t
redisSSLWrite
(
redisContext
*
c
)
{
redisSSL
Context
*
rssl
=
c
->
priv
data
;
static
ssize_
t
redisSSLWrite
(
redisContext
*
c
)
{
redisSSL
*
rssl
=
c
->
priv
ctx
;
size_t
len
=
rssl
->
lastLen
?
rssl
->
lastLen
:
sdslen
(
c
->
obuf
);
int
rv
=
SSL_write
(
rssl
->
ssl
,
c
->
obuf
,
len
);
...
...
@@ -380,7 +458,7 @@ static int redisSSLWrite(redisContext *c) {
static
void
redisSSLAsyncRead
(
redisAsyncContext
*
ac
)
{
int
rv
;
redisSSL
Context
*
rssl
=
ac
->
c
.
priv
data
;
redisSSL
*
rssl
=
ac
->
c
.
priv
ctx
;
redisContext
*
c
=
&
ac
->
c
;
rssl
->
wantRead
=
0
;
...
...
@@ -410,7 +488,7 @@ static void redisSSLAsyncRead(redisAsyncContext *ac) {
static
void
redisSSLAsyncWrite
(
redisAsyncContext
*
ac
)
{
int
rv
,
done
=
0
;
redisSSL
Context
*
rssl
=
ac
->
c
.
priv
data
;
redisSSL
*
rssl
=
ac
->
c
.
priv
ctx
;
redisContext
*
c
=
&
ac
->
c
;
rssl
->
pendingWrite
=
0
;
...
...
@@ -439,7 +517,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
}
redisContextFuncs
redisContextSSLFuncs
=
{
.
free_priv
data
=
redisSSLFree
Context
,
.
free_priv
ctx
=
redisSSLFree
,
.
async_read
=
redisSSLAsyncRead
,
.
async_write
=
redisSSLAsyncWrite
,
.
read
=
redisSSLRead
,
...
...
deps/hiredis/test.c
View file @
3f073b1d
This diff is collapsed.
Click to expand it.
deps/hiredis/test.sh
View file @
3f073b1d
...
...
@@ -4,7 +4,9 @@ REDIS_SERVER=${REDIS_SERVER:-redis-server}
REDIS_PORT
=
${
REDIS_PORT
:-
56379
}
REDIS_SSL_PORT
=
${
REDIS_SSL_PORT
:-
56443
}
TEST_SSL
=
${
TEST_SSL
:-
0
}
SKIPS_AS_FAILS
=
${
SKIPS_AS_FAILS
-
:0
}
SSL_TEST_ARGS
=
SKIPS_ARG
=
tmpdir
=
$(
mktemp
-d
)
PID_FILE
=
${
tmpdir
}
/hiredis-test-redis.pid
...
...
@@ -67,4 +69,10 @@ fi
cat
${
tmpdir
}
/redis.conf
${
REDIS_SERVER
}
${
tmpdir
}
/redis.conf
${
TEST_PREFIX
:-}
./hiredis-test
-h
127.0.0.1
-p
${
REDIS_PORT
}
-s
${
SOCK_FILE
}
${
SSL_TEST_ARGS
}
# Wait until we detect the unix socket
while
[
!
-S
"
${
SOCK_FILE
}
"
]
;
do
sleep
1
;
done
# Treat skips as failures if directed
[
"
$SKIPS_AS_FAILS
"
=
1
]
&&
SKIPS_ARG
=
"--skips-as-fails"
${
TEST_PREFIX
:-}
./hiredis-test
-h
127.0.0.1
-p
${
REDIS_PORT
}
-s
${
SOCK_FILE
}
${
SSL_TEST_ARGS
}
${
SKIPS_ARG
}
src/redis-cli.c
View file @
3f073b1d
This diff is collapsed.
Click to expand it.
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