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
hiredis
Commits
08efa465
Commit
08efa465
authored
Nov 27, 2017
by
Mark Nunberg
Browse files
SSL for async I/O
parent
ba947bc9
Changes
5
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
08efa465
...
...
@@ -4,7 +4,8 @@
# This file is released under the BSD license, see the COPYING file
OBJ
=
net.o hiredis.o sds.o async.o read.o sslio.o
EXAMPLES
=
hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-ssl
EXAMPLES
=
hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib
\
hiredis-example-ssl hiredis-example-libevent-ssl
TESTS
=
hiredis-test
LIBNAME
=
libhiredis
PKGCONFNAME
=
hiredis.pc
...
...
@@ -94,6 +95,9 @@ static: $(STLIBNAME)
hiredis-example-libevent
:
examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
$(CC)
-o
examples/
$@
$(REAL_CFLAGS)
$(REAL_LDFLAGS)
-I
.
$<
-levent
$(STLIBNAME)
hiredis-example-libevent-ssl
:
examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME)
$(CC)
-o
examples/
$@
$(REAL_CFLAGS)
$(REAL_LDFLAGS)
-I
.
$<
-levent
$(STLIBNAME)
hiredis-example-libev
:
examples/example-libev.c adapters/libev.h $(STLIBNAME)
$(CC)
-o
examples/
$@
$(REAL_CFLAGS)
$(REAL_LDFLAGS)
-I
.
$<
-lev
$(STLIBNAME)
...
...
async.c
View file @
08efa465
...
...
@@ -40,6 +40,7 @@
#include "net.h"
#include "dict.c"
#include "sds.h"
#include "sslio.h"
#define _EL_ADD_READ(ctx) do { \
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
...
...
@@ -524,6 +525,87 @@ static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
}
}
#ifndef HIREDIS_NOSSL
/**
* Handle SSL when socket becomes available for reading. This also handles
* read-while-write and write-while-read
*/
static
void
asyncSslRead
(
redisAsyncContext
*
ac
)
{
int
rv
;
redisSsl
*
ssl
=
ac
->
c
.
ssl
;
redisContext
*
c
=
&
ac
->
c
;
ssl
->
wantRead
=
0
;
if
(
ssl
->
pendingWrite
)
{
int
done
;
/* This is probably just a write event */
ssl
->
pendingWrite
=
0
;
rv
=
redisBufferWrite
(
c
,
&
done
);
if
(
rv
==
REDIS_ERR
)
{
__redisAsyncDisconnect
(
ac
);
return
;
}
else
if
(
!
done
)
{
_EL_ADD_WRITE
(
ac
);
}
}
rv
=
redisBufferRead
(
c
);
if
(
rv
==
REDIS_ERR
)
{
__redisAsyncDisconnect
(
ac
);
}
else
{
_EL_ADD_READ
(
ac
);
redisProcessCallbacks
(
ac
);
}
}
/**
* Handle SSL when socket becomes available for writing
*/
static
void
asyncSslWrite
(
redisAsyncContext
*
ac
)
{
int
rv
,
done
=
0
;
redisSsl
*
ssl
=
ac
->
c
.
ssl
;
redisContext
*
c
=
&
ac
->
c
;
ssl
->
pendingWrite
=
0
;
rv
=
redisBufferWrite
(
c
,
&
done
);
if
(
rv
==
REDIS_ERR
)
{
__redisAsyncDisconnect
(
ac
);
return
;
}
if
(
!
done
)
{
if
(
ssl
->
wantRead
)
{
/* Need to read-before-write */
ssl
->
pendingWrite
=
1
;
_EL_DEL_WRITE
(
ac
);
}
else
{
/* No extra reads needed, just need to write more */
_EL_ADD_WRITE
(
ac
);
}
}
else
{
/* Already done! */
_EL_DEL_WRITE
(
ac
);
}
/* Always reschedule a read */
_EL_ADD_READ
(
ac
);
}
#else
/* Just so we're able to compile */
static
void
asyncSslRead
(
redisAsyncContext
*
ac
)
{
abort
();
(
void
)
ac
;
}
static
void
asyncSslWrite
(
redisAsyncContext
*
ac
)
{
abort
();
(
void
)
ac
;
}
#endif
/* This function should be called when the socket is readable.
* It processes all replies that can be read and executes their callbacks.
*/
...
...
@@ -539,6 +621,11 @@ void redisAsyncHandleRead(redisAsyncContext *ac) {
return
;
}
if
(
c
->
flags
&
REDIS_SSL
)
{
asyncSslRead
(
ac
);
return
;
}
if
(
redisBufferRead
(
c
)
==
REDIS_ERR
)
{
__redisAsyncDisconnect
(
ac
);
}
else
{
...
...
@@ -561,6 +648,11 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) {
return
;
}
if
(
c
->
flags
&
REDIS_SSL
)
{
asyncSslWrite
(
ac
);
return
;
}
if
(
redisBufferWrite
(
c
,
&
done
)
==
REDIS_ERR
)
{
__redisAsyncDisconnect
(
ac
);
}
else
{
...
...
examples/example-libevent-ssl.c
0 → 100644
View file @
08efa465
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <hiredis.h>
#include <async.h>
#include <adapters/libevent.h>
void
getCallback
(
redisAsyncContext
*
c
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
if
(
reply
==
NULL
)
return
;
printf
(
"argv[%s]: %s
\n
"
,
(
char
*
)
privdata
,
reply
->
str
);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect
(
c
);
}
void
connectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
if
(
status
!=
REDIS_OK
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
;
}
printf
(
"Connected...
\n
"
);
}
void
disconnectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
if
(
status
!=
REDIS_OK
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
;
}
printf
(
"Disconnected...
\n
"
);
}
int
main
(
int
argc
,
char
**
argv
)
{
signal
(
SIGPIPE
,
SIG_IGN
);
struct
event_base
*
base
=
event_base_new
();
if
(
argc
<
5
)
{
fprintf
(
stderr
,
"Usage: %s <key> <host> <port> <cert> <certKey> [ca]
\n
"
,
argv
[
0
]);
exit
(
1
);
}
const
char
*
value
=
argv
[
1
];
size_t
nvalue
=
strlen
(
value
);
const
char
*
hostname
=
argv
[
2
];
int
port
=
atoi
(
argv
[
3
]);
const
char
*
cert
=
argv
[
4
];
const
char
*
certKey
=
argv
[
5
];
const
char
*
caCert
=
argc
>
5
?
argv
[
6
]
:
NULL
;
redisAsyncContext
*
c
=
redisAsyncConnect
(
hostname
,
port
);
if
(
c
->
err
)
{
/* Let *c leak for now... */
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
1
;
}
if
(
redisSecureConnection
(
&
c
->
c
,
caCert
,
cert
,
certKey
)
!=
REDIS_OK
)
{
printf
(
"SSL Error!
\n
"
);
exit
(
1
);
}
redisLibeventAttach
(
c
,
base
);
redisAsyncSetConnectCallback
(
c
,
connectCallback
);
redisAsyncSetDisconnectCallback
(
c
,
disconnectCallback
);
redisAsyncCommand
(
c
,
NULL
,
NULL
,
"SET key %b"
,
value
,
nvalue
);
redisAsyncCommand
(
c
,
getCallback
,
(
char
*
)
"end-1"
,
"GET key"
);
event_base_dispatch
(
base
);
return
0
;
}
sslio.c
View file @
08efa465
...
...
@@ -99,7 +99,7 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath,
redisSsl
*
s
=
c
->
ssl
;
s
->
ctx
=
SSL_CTX_new
(
SSLv23_client_method
());
/*
SSL_CTX_set_info_callback(s->ctx, sslLogCallback);
*/
SSL_CTX_set_info_callback
(
s
->
ctx
,
sslLogCallback
);
SSL_CTX_set_mode
(
s
->
ctx
,
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
);
SSL_CTX_set_options
(
s
->
ctx
,
SSL_OP_NO_SSLv2
|
SSL_OP_NO_SSLv3
);
SSL_CTX_set_verify
(
s
->
ctx
,
SSL_VERIFY_PEER
,
NULL
);
...
...
@@ -153,6 +153,22 @@ int redisSslCreate(redisContext *c, const char *capath, const char *certpath,
return
REDIS_ERR
;
}
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
*/
if
(
rv
==
SSL_ERROR_WANT_READ
)
{
rssl
->
wantRead
=
1
;
return
1
;
}
else
if
(
rv
==
SSL_ERROR_WANT_WRITE
)
{
rssl
->
pendingWrite
=
1
;
return
1
;
}
else
{
return
0
;
}
}
int
redisSslRead
(
redisContext
*
c
,
char
*
buf
,
size_t
bufcap
)
{
int
nread
=
SSL_read
(
c
->
ssl
->
ssl
,
buf
,
bufcap
);
if
(
nread
>
0
)
{
...
...
@@ -162,7 +178,7 @@ int redisSslRead(redisContext *c, char *buf, size_t bufcap) {
return
-
1
;
}
else
{
int
err
=
SSL_get_error
(
c
->
ssl
->
ssl
,
nread
);
if
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
)
{
if
(
maybeCheckWant
(
c
->
ssl
,
err
)
)
{
return
0
;
}
else
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
...
...
@@ -181,7 +197,7 @@ int redisSslWrite(redisContext *c) {
c
->
ssl
->
lastLen
=
len
;
int
err
=
SSL_get_error
(
c
->
ssl
->
ssl
,
rv
);
if
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
)
{
if
(
maybeCheckWant
(
c
->
ssl
,
err
)
)
{
return
0
;
}
else
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
...
...
sslio.h
View file @
08efa465
...
...
@@ -33,6 +33,15 @@ typedef struct redisSsl {
* previously called with in the event of an SSL_read/SSL_write situation
*/
size_t
lastLen
;
/** Whether the SSL layer requires read (possibly before a write) */
int
wantRead
;
/**
* Whether a write was requested prior to a read. If set, the write()
* should resume whenever a read takes place, if possible
*/
int
pendingWrite
;
}
redisSsl
;
struct
redisContext
;
...
...
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