aboutsummaryrefslogtreecommitdiff
path: root/bufferevent_openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'bufferevent_openssl.c')
-rw-r--r--bufferevent_openssl.c75
1 files changed, 49 insertions, 26 deletions
diff --git a/bufferevent_openssl.c b/bufferevent_openssl.c
index da3963af06a8..b51b834bca7f 100644
--- a/bufferevent_openssl.c
+++ b/bufferevent_openssl.c
@@ -63,7 +63,6 @@
#include "bufferevent-internal.h"
#include "log-internal.h"
-#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "openssl-compat.h"
@@ -155,7 +154,7 @@ bio_bufferevent_read(BIO *b, char *out, int outlen)
return r;
}
-/* Called to write data info the BIO */
+/* Called to write data into the BIO */
static int
bio_bufferevent_write(BIO *b, const char *in, int inlen)
{
@@ -251,7 +250,7 @@ BIO_s_bufferevent(void)
/* Create a new BIO to wrap communication around a bufferevent. If close_flag
* is true, the bufferevent will be freed when the BIO is closed. */
static BIO *
-BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
+BIO_new_bufferevent(struct bufferevent *bufferevent)
{
BIO *result;
if (!bufferevent)
@@ -260,7 +259,9 @@ BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
return NULL;
BIO_set_init(result, 1);
BIO_set_data(result, bufferevent);
- BIO_set_shutdown(result, close_flag ? 1 : 0);
+ /* We don't tell the BIO to close the bufferevent; we do it ourselves on
+ * be_openssl_destruct() */
+ BIO_set_shutdown(result, 0);
return result;
}
@@ -354,11 +355,11 @@ static inline struct bufferevent_openssl *
upcast(struct bufferevent *bev)
{
struct bufferevent_openssl *bev_o;
- if (bev->be_ops != &bufferevent_ops_openssl)
+ if (!BEV_IS_OPENSSL(bev))
return NULL;
bev_o = (void*)( ((char*)bev) -
evutil_offsetof(struct bufferevent_openssl, bev.bev));
- EVUTIL_ASSERT(bev_o->bev.bev.be_ops == &bufferevent_ops_openssl);
+ EVUTIL_ASSERT(BEV_IS_OPENSSL(&bev_o->bev.bev));
return bev_o;
}
@@ -510,12 +511,15 @@ conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
/* IO error; possibly a dirty shutdown. */
if ((ret == 0 || ret == -1) && ERR_peek_error() == 0)
dirty_shutdown = 1;
+ put_error(bev_ssl, errcode);
break;
case SSL_ERROR_SSL:
/* Protocol error. */
+ put_error(bev_ssl, errcode);
break;
case SSL_ERROR_WANT_X509_LOOKUP:
/* XXXX handle this. */
+ put_error(bev_ssl, errcode);
break;
case SSL_ERROR_NONE:
case SSL_ERROR_WANT_READ:
@@ -803,7 +807,7 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
if (bev_ssl->bev.read_suspended)
break;
-
+
/* Read all pending data. This won't hit the network
* again, and will (most importantly) put us in a state
* where we don't need to read anything else until the
@@ -963,8 +967,8 @@ be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
}
-static int
-be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, int fd)
+static evutil_socket_t
+be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
{
if (!bev_ssl->underlying) {
struct bufferevent *bev = &bev_ssl->bev.bev;
@@ -1030,7 +1034,7 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
decrement_buckets(bev_ssl);
if (r==1) {
- int fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
+ evutil_socket_t fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
/* We're done! */
bev_ssl->state = BUFFEREVENT_SSL_OPEN;
set_open_callbacks(bev_ssl, fd); /* XXXX handle failure */
@@ -1228,7 +1232,7 @@ be_openssl_destruct(struct bufferevent *bev)
if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
if (! bev_ssl->underlying) {
- evutil_socket_t fd = -1;
+ evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
BIO *bio = SSL_get_wbio(bev_ssl->ssl);
if (bio)
fd = BIO_get_fd(bio, NULL);
@@ -1261,17 +1265,21 @@ be_openssl_flush(struct bufferevent *bufev,
static int
be_openssl_set_fd(struct bufferevent_openssl *bev_ssl,
- enum bufferevent_ssl_state state, int fd)
+ enum bufferevent_ssl_state state, evutil_socket_t fd)
{
bev_ssl->state = state;
switch (state) {
case BUFFEREVENT_SSL_ACCEPTING:
+ if (!SSL_clear(bev_ssl->ssl))
+ return -1;
SSL_set_accept_state(bev_ssl->ssl);
if (set_handshake_callbacks(bev_ssl, fd) < 0)
return -1;
break;
case BUFFEREVENT_SSL_CONNECTING:
+ if (!SSL_clear(bev_ssl->ssl))
+ return -1;
SSL_set_connect_state(bev_ssl->ssl);
if (set_handshake_callbacks(bev_ssl, fd) < 0)
return -1;
@@ -1296,11 +1304,11 @@ be_openssl_ctrl(struct bufferevent *bev,
case BEV_CTRL_SET_FD:
if (!bev_ssl->underlying) {
BIO *bio;
- bio = BIO_new_socket(data->fd, 0);
+ bio = BIO_new_socket((int)data->fd, 0);
SSL_set_bio(bev_ssl->ssl, bio, bio);
} else {
BIO *bio;
- if (!(bio = BIO_new_bufferevent(bev_ssl->underlying, 0)))
+ if (!(bio = BIO_new_bufferevent(bev_ssl->underlying)))
return -1;
SSL_set_bio(bev_ssl->ssl, bio, bio);
}
@@ -1343,8 +1351,9 @@ bufferevent_openssl_new_impl(struct event_base *base,
struct bufferevent_private *bev_p = NULL;
int tmp_options = options & ~BEV_OPT_THREADSAFE;
+ /* Only one can be set. */
if (underlying != NULL && fd >= 0)
- return NULL; /* Only one can be set. */
+ goto err;
if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
goto err;
@@ -1392,8 +1401,12 @@ bufferevent_openssl_new_impl(struct event_base *base,
return &bev_ssl->bev.bev;
err:
- if (bev_ssl)
+ if (options & BEV_OPT_CLOSE_ON_FREE)
+ SSL_free(ssl);
+ if (bev_ssl) {
+ bev_ssl->ssl = NULL;
bufferevent_free(&bev_ssl->bev.bev);
+ }
return NULL;
}
@@ -1404,19 +1417,24 @@ bufferevent_openssl_filter_new(struct event_base *base,
enum bufferevent_ssl_state state,
int options)
{
- /* We don't tell the BIO to close the bufferevent; we do it ourselves
- * on be_openssl_destruct */
- int close_flag = 0; /* options & BEV_OPT_CLOSE_ON_FREE; */
BIO *bio;
+ struct bufferevent *bev;
+
if (!underlying)
- return NULL;
- if (!(bio = BIO_new_bufferevent(underlying, close_flag)))
- return NULL;
+ goto err;
+ if (!(bio = BIO_new_bufferevent(underlying)))
+ goto err;
SSL_set_bio(ssl, bio, bio);
- return bufferevent_openssl_new_impl(
+ bev = bufferevent_openssl_new_impl(
base, underlying, -1, ssl, state, options);
+ return bev;
+
+err:
+ if (options & BEV_OPT_CLOSE_ON_FREE)
+ SSL_free(ssl);
+ return NULL;
}
struct bufferevent *
@@ -1443,14 +1461,14 @@ bufferevent_openssl_socket_new(struct event_base *base,
} else {
/* We specified an fd different from that of the SSL.
This is probably an error on our part. Fail. */
- return NULL;
+ goto err;
}
- (void) BIO_set_close(bio, 0);
+ BIO_set_close(bio, 0);
} else {
/* The SSL isn't configured with a BIO with an fd. */
if (fd >= 0) {
/* ... and we have an fd we want to use. */
- bio = BIO_new_socket(fd, 0);
+ bio = BIO_new_socket((int)fd, 0);
SSL_set_bio(ssl, bio, bio);
} else {
/* Leave the fd unset. */
@@ -1459,6 +1477,11 @@ bufferevent_openssl_socket_new(struct event_base *base,
return bufferevent_openssl_new_impl(
base, NULL, fd, ssl, state, options);
+
+err:
+ if (options & BEV_OPT_CLOSE_ON_FREE)
+ SSL_free(ssl);
+ return NULL;
}
int