aboutsummaryrefslogtreecommitdiff
path: root/bufferevent_openssl.c
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2017-08-07 14:18:18 -0700
committerElliott Hughes <enh@google.com>2017-08-07 16:58:18 -0700
commit2a572d125a91a4aafd3ad8ce87259fc640fa0763 (patch)
treebd05e575a4a2629cc420c5e2bc54f176fee611ab /bufferevent_openssl.c
parent596447c7ff2881a67e7082c905112584c3e61a17 (diff)
downloadlibevent-2a572d125a91a4aafd3ad8ce87259fc640fa0763.tar.gz
Upgrade to 2.1.8-stable (2017-01-22).
Bug: N/A Test: builds Change-Id: Idbbdc1db3d01984a4f4b60f8fdf455140b6b7ca6
Diffstat (limited to 'bufferevent_openssl.c')
-rw-r--r--bufferevent_openssl.c455
1 files changed, 251 insertions, 204 deletions
diff --git a/bufferevent_openssl.c b/bufferevent_openssl.c
index 7582d9b..da3963a 100644
--- a/bufferevent_openssl.c
+++ b/bufferevent_openssl.c
@@ -24,11 +24,17 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
+// Get rid of OSX 10.7 and greater deprecation warnings.
+#if defined(__APPLE__) && defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
-#ifdef _EVENT_HAVE_SYS_TIME_H
+#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -36,14 +42,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#ifdef _EVENT_HAVE_STDARG_H
+#ifdef EVENT__HAVE_STDARG_H
#include <stdarg.h>
#endif
-#ifdef _EVENT_HAVE_UNISTD_H
+#ifdef EVENT__HAVE_UNISTD_H
#include <unistd.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
@@ -60,6 +66,7 @@
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
+#include "openssl-compat.h"
/*
* Define an OpenSSL bio that targets a bufferevent.
@@ -103,10 +110,8 @@ print_err(int val)
static int
bio_bufferevent_new(BIO *b)
{
- b->init = 0;
- b->num = -1;
- b->ptr = NULL; /* We'll be putting the bufferevent in this field.*/
- b->flags = 0;
+ BIO_set_init(b, 0);
+ BIO_set_data(b, NULL); /* We'll be putting the bufferevent in this field.*/
return 1;
}
@@ -116,12 +121,10 @@ bio_bufferevent_free(BIO *b)
{
if (!b)
return 0;
- if (b->shutdown) {
- if (b->init && b->ptr)
- bufferevent_free(b->ptr);
- b->init = 0;
- b->flags = 0;
- b->ptr = NULL;
+ if (BIO_get_shutdown(b)) {
+ if (BIO_get_init(b) && BIO_get_data(b))
+ bufferevent_free(BIO_get_data(b));
+ BIO_free(b);
}
return 1;
}
@@ -137,10 +140,10 @@ bio_bufferevent_read(BIO *b, char *out, int outlen)
if (!out)
return 0;
- if (!b->ptr)
+ if (!BIO_get_data(b))
return -1;
- input = bufferevent_get_input(b->ptr);
+ input = bufferevent_get_input(BIO_get_data(b));
if (evbuffer_get_length(input) == 0) {
/* If there's no data to read, say so. */
BIO_set_retry_read(b);
@@ -156,13 +159,13 @@ bio_bufferevent_read(BIO *b, char *out, int outlen)
static int
bio_bufferevent_write(BIO *b, const char *in, int inlen)
{
- struct bufferevent *bufev = b->ptr;
+ struct bufferevent *bufev = BIO_get_data(b);
struct evbuffer *output;
size_t outlen;
BIO_clear_retry_flags(b);
- if (!b->ptr)
+ if (!BIO_get_data(b))
return -1;
output = bufferevent_get_output(bufev);
@@ -188,15 +191,15 @@ bio_bufferevent_write(BIO *b, const char *in, int inlen)
static long
bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
{
- struct bufferevent *bufev = b->ptr;
+ struct bufferevent *bufev = BIO_get_data(b);
long ret = 1;
switch (cmd) {
case BIO_CTRL_GET_CLOSE:
- ret = b->shutdown;
+ ret = BIO_get_shutdown(b);
break;
case BIO_CTRL_SET_CLOSE:
- b->shutdown = (int)num;
+ BIO_set_shutdown(b, (int)num);
break;
case BIO_CTRL_PENDING:
ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
@@ -225,23 +228,24 @@ bio_bufferevent_puts(BIO *b, const char *s)
}
/* Method table for the bufferevent BIO */
-static BIO_METHOD methods_bufferevent = {
- BIO_TYPE_LIBEVENT, "bufferevent",
- bio_bufferevent_write,
- bio_bufferevent_read,
- bio_bufferevent_puts,
- NULL /* bio_bufferevent_gets */,
- bio_bufferevent_ctrl,
- bio_bufferevent_new,
- bio_bufferevent_free,
- NULL /* callback_ctrl */,
-};
+static BIO_METHOD *methods_bufferevent;
/* Return the method table for the bufferevents BIO */
static BIO_METHOD *
BIO_s_bufferevent(void)
{
- return &methods_bufferevent;
+ if (methods_bufferevent == NULL) {
+ methods_bufferevent = BIO_meth_new(BIO_TYPE_LIBEVENT, "bufferevent");
+ if (methods_bufferevent == NULL)
+ return NULL;
+ BIO_meth_set_write(methods_bufferevent, bio_bufferevent_write);
+ BIO_meth_set_read(methods_bufferevent, bio_bufferevent_read);
+ BIO_meth_set_puts(methods_bufferevent, bio_bufferevent_puts);
+ BIO_meth_set_ctrl(methods_bufferevent, bio_bufferevent_ctrl);
+ BIO_meth_set_create(methods_bufferevent, bio_bufferevent_new);
+ BIO_meth_set_destroy(methods_bufferevent, bio_bufferevent_free);
+ }
+ return methods_bufferevent;
}
/* Create a new BIO to wrap communication around a bufferevent. If close_flag
@@ -254,9 +258,9 @@ BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
return NULL;
if (!(result = BIO_new(BIO_s_bufferevent())))
return NULL;
- result->init = 1;
- result->ptr = bufferevent;
- result->shutdown = close_flag ? 1 : 0;
+ BIO_set_init(result, 1);
+ BIO_set_data(result, bufferevent);
+ BIO_set_shutdown(result, close_flag ? 1 : 0);
return result;
}
@@ -312,19 +316,20 @@ struct bufferevent_openssl {
unsigned read_blocked_on_write : 1;
/* When we next get data, we should say "write" instead of "read". */
unsigned write_blocked_on_read : 1;
- /* XXX */
+ /* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
unsigned allow_dirty_shutdown : 1;
- /* XXXX */
- unsigned fd_is_set : 1;
/* XXX */
unsigned n_errors : 2;
/* Are we currently connecting, accepting, or doing IO? */
unsigned state : 2;
+ /* If we reset fd, we sould reset state too */
+ unsigned old_state : 2;
};
static int be_openssl_enable(struct bufferevent *, short);
static int be_openssl_disable(struct bufferevent *, short);
+static void be_openssl_unlink(struct bufferevent *);
static void be_openssl_destruct(struct bufferevent *);
static int be_openssl_adj_timeouts(struct bufferevent *);
static int be_openssl_flush(struct bufferevent *bufev,
@@ -336,6 +341,7 @@ const struct bufferevent_ops bufferevent_ops_openssl = {
evutil_offsetof(struct bufferevent_openssl, bev.bev),
be_openssl_enable,
be_openssl_disable,
+ be_openssl_unlink,
be_openssl_destruct,
be_openssl_adj_timeouts,
be_openssl_flush,
@@ -376,15 +382,15 @@ static int
start_reading(struct bufferevent_openssl *bev_ssl)
{
if (bev_ssl->underlying) {
- bufferevent_unsuspend_read(bev_ssl->underlying,
+ bufferevent_unsuspend_read_(bev_ssl->underlying,
BEV_SUSPEND_FILT_READ);
return 0;
} else {
struct bufferevent *bev = &bev_ssl->bev.bev;
int r;
- r = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
+ r = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
if (r == 0 && bev_ssl->read_blocked_on_write)
- r = _bufferevent_add_event(&bev->ev_write,
+ r = bufferevent_add_event_(&bev->ev_write,
&bev->timeout_write);
return r;
}
@@ -398,12 +404,15 @@ start_writing(struct bufferevent_openssl *bev_ssl)
{
int r = 0;
if (bev_ssl->underlying) {
- ;
+ if (bev_ssl->write_blocked_on_read) {
+ bufferevent_unsuspend_read_(bev_ssl->underlying,
+ BEV_SUSPEND_FILT_READ);
+ }
} else {
struct bufferevent *bev = &bev_ssl->bev.bev;
- r = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
+ r = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
if (!r && bev_ssl->write_blocked_on_read)
- r = _bufferevent_add_event(&bev->ev_read,
+ r = bufferevent_add_event_(&bev->ev_read,
&bev->timeout_read);
}
return r;
@@ -415,7 +424,7 @@ stop_reading(struct bufferevent_openssl *bev_ssl)
if (bev_ssl->write_blocked_on_read)
return;
if (bev_ssl->underlying) {
- bufferevent_suspend_read(bev_ssl->underlying,
+ bufferevent_suspend_read_(bev_ssl->underlying,
BEV_SUSPEND_FILT_READ);
} else {
struct bufferevent *bev = &bev_ssl->bev.bev;
@@ -429,7 +438,8 @@ stop_writing(struct bufferevent_openssl *bev_ssl)
if (bev_ssl->read_blocked_on_write)
return;
if (bev_ssl->underlying) {
- ;
+ bufferevent_unsuspend_read_(bev_ssl->underlying,
+ BEV_SUSPEND_FILT_READ);
} else {
struct bufferevent *bev = &bev_ssl->bev.bev;
event_del(&bev->ev_write);
@@ -482,7 +492,7 @@ clear_wbor(struct bufferevent_openssl *bev_ssl)
}
static void
-conn_closed(struct bufferevent_openssl *bev_ssl, int errcode, int ret)
+conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
{
int event = BEV_EVENT_ERROR;
int dirty_shutdown = 0;
@@ -498,7 +508,7 @@ conn_closed(struct bufferevent_openssl *bev_ssl, int errcode, int ret)
break;
case SSL_ERROR_SYSCALL:
/* IO error; possibly a dirty shutdown. */
- if (ret == 0 && ERR_peek_error() == 0)
+ if ((ret == 0 || ret == -1) && ERR_peek_error() == 0)
dirty_shutdown = 1;
break;
case SSL_ERROR_SSL:
@@ -528,16 +538,20 @@ conn_closed(struct bufferevent_openssl *bev_ssl, int errcode, int ret)
stop_reading(bev_ssl);
stop_writing(bev_ssl);
- _bufferevent_run_eventcb(&bev_ssl->bev.bev, event);
+ /* when is BEV_EVENT_{READING|WRITING} */
+ event = when | event;
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
}
static void
init_bio_counts(struct bufferevent_openssl *bev_ssl)
{
- bev_ssl->counts.n_written =
- BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
- bev_ssl->counts.n_read =
- BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
+ BIO *rbio, *wbio;
+
+ wbio = SSL_get_wbio(bev_ssl->ssl);
+ bev_ssl->counts.n_written = wbio ? BIO_number_written(wbio) : 0;
+ rbio = SSL_get_rbio(bev_ssl->ssl);
+ bev_ssl->counts.n_read = rbio ? BIO_number_read(rbio) : 0;
}
static inline void
@@ -549,9 +563,9 @@ decrement_buckets(struct bufferevent_openssl *bev_ssl)
unsigned long w = num_w - bev_ssl->counts.n_written;
unsigned long r = num_r - bev_ssl->counts.n_read;
if (w)
- _bufferevent_decrement_write_buckets(&bev_ssl->bev, w);
+ bufferevent_decrement_write_buckets_(&bev_ssl->bev, w);
if (r)
- _bufferevent_decrement_read_buckets(&bev_ssl->bev, r);
+ bufferevent_decrement_read_buckets_(&bev_ssl->bev, r);
bev_ssl->counts.n_written = num_w;
bev_ssl->counts.n_read = num_r;
}
@@ -574,7 +588,7 @@ do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
if (bev_ssl->bev.read_suspended)
return 0;
- atmost = _bufferevent_get_read_max(&bev_ssl->bev);
+ atmost = bufferevent_get_read_max_(&bev_ssl->bev);
if (n_to_read > atmost)
n_to_read = atmost;
@@ -585,6 +599,7 @@ do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
for (i=0; i<n; ++i) {
if (bev_ssl->bev.read_suspended)
break;
+ ERR_clear_error();
r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
if (r>0) {
result |= OP_MADE_PROGRESS;
@@ -612,7 +627,7 @@ do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
return OP_ERR | result;
break;
default:
- conn_closed(bev_ssl, err, r);
+ conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
break;
}
result |= OP_BLOCKED;
@@ -643,7 +658,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
if (bev_ssl->last_write > 0)
atmost = bev_ssl->last_write;
else
- atmost = _bufferevent_get_write_max(&bev_ssl->bev);
+ atmost = bufferevent_get_write_max_(&bev_ssl->bev);
n = evbuffer_peek(output, atmost, NULL, space, 8);
if (n < 0)
@@ -661,6 +676,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
if (space[i].iov_len == 0)
continue;
+ ERR_clear_error();
r = SSL_write(bev_ssl->ssl, space[i].iov_base,
space[i].iov_len);
if (r > 0) {
@@ -691,7 +707,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
bev_ssl->last_write = space[i].iov_len;
break;
default:
- conn_closed(bev_ssl, err, r);
+ conn_closed(bev_ssl, BEV_EVENT_WRITING, err, r);
bev_ssl->last_write = -1;
break;
}
@@ -704,8 +720,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
if (bev_ssl->underlying)
BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
- if (evbuffer_get_length(output) <= bev->wm_write.low)
- _bufferevent_run_writecb(bev);
+ bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
}
return result;
}
@@ -749,7 +764,7 @@ bytes_to_read(struct bufferevent_openssl *bev)
}
/* Respect the rate limit */
- limit = _bufferevent_get_read_max(&bev->bev);
+ limit = bufferevent_get_read_max_(&bev->bev);
if (result > limit) {
result = limit;
}
@@ -819,11 +834,8 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
if (all_result_flags & OP_MADE_PROGRESS) {
struct bufferevent *bev = &bev_ssl->bev.bev;
- struct evbuffer *input = bev->input;
- if (evbuffer_get_length(input) >= bev->wm_read.low) {
- _bufferevent_run_readcb(bev);
- }
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
}
if (!bev_ssl->underlying) {
@@ -847,11 +859,8 @@ consider_writing(struct bufferevent_openssl *bev_ssl)
r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
if (r & OP_MADE_PROGRESS) {
struct bufferevent *bev = &bev_ssl->bev.bev;
- struct evbuffer *input = bev->input;
- if (evbuffer_get_length(input) >= bev->wm_read.low) {
- _bufferevent_run_readcb(bev);
- }
+ bufferevent_trigger_nolock_(bev, EV_READ, 0);
}
if (r & (OP_ERR|OP_BLOCKED))
break;
@@ -923,35 +932,47 @@ be_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
eat it. */
}
if (event)
- _bufferevent_run_eventcb(&bev_ssl->bev.bev, event);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
}
static void
be_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
{
struct bufferevent_openssl *bev_ssl = ptr;
- _bufferevent_incref_and_lock(&bev_ssl->bev.bev);
+ bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
if (what == EV_TIMEOUT) {
- _bufferevent_run_eventcb(&bev_ssl->bev.bev,
- BEV_EVENT_TIMEOUT|BEV_EVENT_READING);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev,
+ BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
} else {
consider_reading(bev_ssl);
}
- _bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
+ bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
}
static void
be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
{
struct bufferevent_openssl *bev_ssl = ptr;
- _bufferevent_incref_and_lock(&bev_ssl->bev.bev);
+ bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
if (what == EV_TIMEOUT) {
- _bufferevent_run_eventcb(&bev_ssl->bev.bev,
- BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev,
+ BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
} else {
consider_writing(bev_ssl);
}
- _bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
+ bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
+}
+
+static int
+be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, int fd)
+{
+ if (!bev_ssl->underlying) {
+ struct bufferevent *bev = &bev_ssl->bev.bev;
+ if (event_initialized(&bev->ev_read) && fd < 0) {
+ fd = event_get_fd(&bev->ev_read);
+ }
+ }
+ return fd;
}
static int
@@ -965,25 +986,27 @@ set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
} else {
struct bufferevent *bev = &bev_ssl->bev.bev;
int rpending=0, wpending=0, r1=0, r2=0;
- if (fd < 0 && bev_ssl->fd_is_set)
- fd = event_get_fd(&bev->ev_read);
- if (bev_ssl->fd_is_set) {
+
+ if (event_initialized(&bev->ev_read)) {
rpending = event_pending(&bev->ev_read, EV_READ, NULL);
wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
+
event_del(&bev->ev_read);
event_del(&bev->ev_write);
}
+
event_assign(&bev->ev_read, bev->ev_base, fd,
- EV_READ|EV_PERSIST, be_openssl_readeventcb, bev_ssl);
+ EV_READ|EV_PERSIST|EV_FINALIZE,
+ be_openssl_readeventcb, bev_ssl);
event_assign(&bev->ev_write, bev->ev_base, fd,
- EV_WRITE|EV_PERSIST, be_openssl_writeeventcb, bev_ssl);
+ EV_WRITE|EV_PERSIST|EV_FINALIZE,
+ be_openssl_writeeventcb, bev_ssl);
+
if (rpending)
- r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
+ r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
if (wpending)
- r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
- if (fd >= 0) {
- bev_ssl->fd_is_set = 1;
- }
+ r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
+
return (r1<0 || r2<0) ? -1 : 0;
}
}
@@ -1000,38 +1023,34 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
return -1;
case BUFFEREVENT_SSL_CONNECTING:
case BUFFEREVENT_SSL_ACCEPTING:
+ ERR_clear_error();
r = SSL_do_handshake(bev_ssl->ssl);
break;
}
decrement_buckets(bev_ssl);
if (r==1) {
+ int fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
/* We're done! */
bev_ssl->state = BUFFEREVENT_SSL_OPEN;
- set_open_callbacks(bev_ssl, -1); /* XXXX handle failure */
+ set_open_callbacks(bev_ssl, fd); /* XXXX handle failure */
/* Call do_read and do_write as needed */
bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
- _bufferevent_run_eventcb(&bev_ssl->bev.bev,
- BEV_EVENT_CONNECTED);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev,
+ BEV_EVENT_CONNECTED, 0);
return 1;
} else {
int err = SSL_get_error(bev_ssl->ssl, r);
print_err(err);
switch (err) {
case SSL_ERROR_WANT_WRITE:
- if (!bev_ssl->underlying) {
- stop_reading(bev_ssl);
- return start_writing(bev_ssl);
- }
- return 0;
+ stop_reading(bev_ssl);
+ return start_writing(bev_ssl);
case SSL_ERROR_WANT_READ:
- if (!bev_ssl->underlying) {
- stop_writing(bev_ssl);
- return start_reading(bev_ssl);
- }
- return 0;
+ stop_writing(bev_ssl);
+ return start_reading(bev_ssl);
default:
- conn_closed(bev_ssl, err, r);
+ conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
return -1;
}
}
@@ -1049,12 +1068,12 @@ be_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
{
struct bufferevent_openssl *bev_ssl = ptr;
- _bufferevent_incref_and_lock(&bev_ssl->bev.bev);
+ bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
if (what & EV_TIMEOUT) {
- _bufferevent_run_eventcb(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT);
+ bufferevent_run_eventcb_(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT, 0);
} else
do_handshake(bev_ssl);/* XXX handle failure */
- _bufferevent_decref_and_unlock(&bev_ssl->bev.bev);
+ bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
}
static int
@@ -1065,26 +1084,31 @@ set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
be_openssl_handshakecb, be_openssl_handshakecb,
be_openssl_eventcb,
bev_ssl);
+
+ if (fd < 0)
+ return 0;
+
+ if (bufferevent_setfd(bev_ssl->underlying, fd))
+ return 1;
+
return do_handshake(bev_ssl);
} else {
struct bufferevent *bev = &bev_ssl->bev.bev;
- int r1=0, r2=0;
- if (fd < 0 && bev_ssl->fd_is_set)
- fd = event_get_fd(&bev->ev_read);
- if (bev_ssl->fd_is_set) {
+
+ if (event_initialized(&bev->ev_read)) {
event_del(&bev->ev_read);
event_del(&bev->ev_write);
}
+
event_assign(&bev->ev_read, bev->ev_base, fd,
- EV_READ|EV_PERSIST, be_openssl_handshakeeventcb, bev_ssl);
+ EV_READ|EV_PERSIST|EV_FINALIZE,
+ be_openssl_handshakeeventcb, bev_ssl);
event_assign(&bev->ev_write, bev->ev_base, fd,
- EV_WRITE|EV_PERSIST, be_openssl_handshakeeventcb, bev_ssl);
- if (fd >= 0) {
- r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
- r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
- bev_ssl->fd_is_set = 1;
- }
- return (r1<0 || r2<0) ? -1 : 0;
+ EV_WRITE|EV_PERSIST|EV_FINALIZE,
+ be_openssl_handshakeeventcb, bev_ssl);
+ if (fd >= 0)
+ bufferevent_enable(bev, bev->enabled);
+ return 0;
}
}
@@ -1097,7 +1121,7 @@ bufferevent_ssl_renegotiate(struct bufferevent *bev)
if (SSL_renegotiate(bev_ssl->ssl) < 0)
return -1;
bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
- if (set_handshake_callbacks(bev_ssl, -1) < 0)
+ if (set_handshake_callbacks(bev_ssl, be_openssl_auto_fd(bev_ssl, -1)) < 0)
return -1;
if (!bev_ssl->underlying)
return do_handshake(bev_ssl);
@@ -1114,12 +1138,14 @@ be_openssl_outbuf_cb(struct evbuffer *buf,
if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) {
if (cbinfo->orig_size == 0)
- r = _bufferevent_add_event(&bev_ssl->bev.bev.ev_write,
+ r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
&bev_ssl->bev.bev.timeout_write);
- consider_writing(bev_ssl);
+
+ if (bev_ssl->underlying)
+ consider_writing(bev_ssl);
}
/* XXX Handle r < 0 */
- (void)r;
+ (void)r;
}
@@ -1129,9 +1155,6 @@ be_openssl_enable(struct bufferevent *bev, short events)
struct bufferevent_openssl *bev_ssl = upcast(bev);
int r1 = 0, r2 = 0;
- if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
- return 0;
-
if (events & EV_READ)
r1 = start_reading(bev_ssl);
if (events & EV_WRITE)
@@ -1155,8 +1178,6 @@ static int
be_openssl_disable(struct bufferevent *bev, short events)
{
struct bufferevent_openssl *bev_ssl = upcast(bev);
- if (bev_ssl->state != BUFFEREVENT_SSL_OPEN)
- return 0;
if (events & EV_READ)
stop_reading(bev_ssl);
@@ -1173,17 +1194,10 @@ be_openssl_disable(struct bufferevent *bev, short events)
}
static void
-be_openssl_destruct(struct bufferevent *bev)
+be_openssl_unlink(struct bufferevent *bev)
{
struct bufferevent_openssl *bev_ssl = upcast(bev);
- if (bev_ssl->underlying) {
- _bufferevent_del_generic_timeout_cbs(bev);
- } else {
- event_del(&bev->ev_read);
- event_del(&bev->ev_write);
- }
-
if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
if (bev_ssl->underlying) {
if (BEV_UPCAST(bev_ssl->underlying)->refcnt < 2) {
@@ -1191,42 +1205,49 @@ be_openssl_destruct(struct bufferevent *bev)
"bufferevent with too few references");
} else {
bufferevent_free(bev_ssl->underlying);
- bev_ssl->underlying = NULL;
+ /* We still have a reference to it, via our
+ * BIO. So we don't drop this. */
+ // bev_ssl->underlying = NULL;
}
- } else {
- evutil_socket_t fd = -1;
- BIO *bio = SSL_get_wbio(bev_ssl->ssl);
- if (bio)
- fd = BIO_get_fd(bio, NULL);
- if (fd >= 0)
- evutil_closesocket(fd);
}
- SSL_free(bev_ssl->ssl);
} else {
if (bev_ssl->underlying) {
if (bev_ssl->underlying->errorcb == be_openssl_eventcb)
bufferevent_setcb(bev_ssl->underlying,
NULL,NULL,NULL,NULL);
- bufferevent_unsuspend_read(bev_ssl->underlying,
+ bufferevent_unsuspend_read_(bev_ssl->underlying,
BEV_SUSPEND_FILT_READ);
}
}
}
+static void
+be_openssl_destruct(struct bufferevent *bev)
+{
+ struct bufferevent_openssl *bev_ssl = upcast(bev);
+
+ if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
+ if (! bev_ssl->underlying) {
+ evutil_socket_t fd = -1;
+ BIO *bio = SSL_get_wbio(bev_ssl->ssl);
+ if (bio)
+ fd = BIO_get_fd(bio, NULL);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+ }
+ SSL_free(bev_ssl->ssl);
+ }
+}
+
static int
be_openssl_adj_timeouts(struct bufferevent *bev)
{
struct bufferevent_openssl *bev_ssl = upcast(bev);
- if (bev_ssl->underlying)
- return _bufferevent_generic_adj_timeouts(bev);
- else {
- int r1=0, r2=0;
- if (event_pending(&bev->ev_read, EV_READ, NULL))
- r1 = _bufferevent_add_event(&bev->ev_read, &bev->timeout_read);
- if (event_pending(&bev->ev_write, EV_WRITE, NULL))
- r2 = _bufferevent_add_event(&bev->ev_write, &bev->timeout_write);
- return (r1<0 || r2<0) ? -1 : 0;
+ if (bev_ssl->underlying) {
+ return bufferevent_generic_adj_timeouts_(bev);
+ } else {
+ return bufferevent_generic_adj_existing_timeouts_(bev);
}
}
@@ -1239,35 +1260,60 @@ be_openssl_flush(struct bufferevent *bufev,
}
static int
+be_openssl_set_fd(struct bufferevent_openssl *bev_ssl,
+ enum bufferevent_ssl_state state, int fd)
+{
+ bev_ssl->state = state;
+
+ switch (state) {
+ case BUFFEREVENT_SSL_ACCEPTING:
+ SSL_set_accept_state(bev_ssl->ssl);
+ if (set_handshake_callbacks(bev_ssl, fd) < 0)
+ return -1;
+ break;
+ case BUFFEREVENT_SSL_CONNECTING:
+ SSL_set_connect_state(bev_ssl->ssl);
+ if (set_handshake_callbacks(bev_ssl, fd) < 0)
+ return -1;
+ break;
+ case BUFFEREVENT_SSL_OPEN:
+ if (set_open_callbacks(bev_ssl, fd) < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
be_openssl_ctrl(struct bufferevent *bev,
enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
{
struct bufferevent_openssl *bev_ssl = upcast(bev);
switch (op) {
case BEV_CTRL_SET_FD:
- if (bev_ssl->underlying)
- return -1;
- {
+ if (!bev_ssl->underlying) {
BIO *bio;
bio = BIO_new_socket(data->fd, 0);
SSL_set_bio(bev_ssl->ssl, bio, bio);
- bev_ssl->fd_is_set = 1;
- }
- if (bev_ssl->state == BUFFEREVENT_SSL_OPEN)
- return set_open_callbacks(bev_ssl, data->fd);
- else {
- return set_handshake_callbacks(bev_ssl, data->fd);
+ } else {
+ BIO *bio;
+ if (!(bio = BIO_new_bufferevent(bev_ssl->underlying, 0)))
+ return -1;
+ SSL_set_bio(bev_ssl->ssl, bio, bio);
}
+
+ return be_openssl_set_fd(bev_ssl, bev_ssl->old_state, data->fd);
case BEV_CTRL_GET_FD:
- if (bev_ssl->underlying)
- return -1;
- if (!bev_ssl->fd_is_set)
- return -1;
- data->fd = event_get_fd(&bev->ev_read);
+ if (bev_ssl->underlying) {
+ data->fd = event_get_fd(&bev_ssl->underlying->ev_read);
+ } else {
+ data->fd = event_get_fd(&bev->ev_read);
+ }
return 0;
case BEV_CTRL_GET_UNDERLYING:
- if (!bev_ssl->underlying)
- return -1;
data->ptr = bev_ssl->underlying;
return 0;
case BEV_CTRL_CANCEL_ALL:
@@ -1305,7 +1351,7 @@ bufferevent_openssl_new_impl(struct event_base *base,
bev_p = &bev_ssl->bev;
- if (bufferevent_init_common(bev_p, base,
+ if (bufferevent_init_common_(bev_p, base,
&bufferevent_ops_openssl, tmp_options) < 0)
goto err;
@@ -1320,52 +1366,28 @@ bufferevent_openssl_new_impl(struct event_base *base,
be_openssl_outbuf_cb, bev_ssl);
if (options & BEV_OPT_THREADSAFE)
- bufferevent_enable_locking(&bev_ssl->bev.bev, NULL);
+ bufferevent_enable_locking_(&bev_ssl->bev.bev, NULL);
if (underlying) {
- _bufferevent_init_generic_timeout_cbs(&bev_ssl->bev.bev);
- bufferevent_incref(underlying);
+ bufferevent_init_generic_timeout_cbs_(&bev_ssl->bev.bev);
+ bufferevent_incref_(underlying);
}
- bev_ssl->state = state;
+ bev_ssl->old_state = state;
bev_ssl->last_write = -1;
init_bio_counts(bev_ssl);
- switch (state) {
- case BUFFEREVENT_SSL_ACCEPTING:
- SSL_set_accept_state(bev_ssl->ssl);
- if (set_handshake_callbacks(bev_ssl, fd) < 0)
- goto err;
- break;
- case BUFFEREVENT_SSL_CONNECTING:
- SSL_set_connect_state(bev_ssl->ssl);
- if (set_handshake_callbacks(bev_ssl, fd) < 0)
- goto err;
- break;
- case BUFFEREVENT_SSL_OPEN:
- if (set_open_callbacks(bev_ssl, fd) < 0)
- goto err;
- break;
- default:
+ fd = be_openssl_auto_fd(bev_ssl, fd);
+ if (be_openssl_set_fd(bev_ssl, state, fd))
goto err;
- }
if (underlying) {
bufferevent_setwatermark(underlying, EV_READ, 0, 0);
bufferevent_enable(underlying, EV_READ|EV_WRITE);
if (state == BUFFEREVENT_SSL_OPEN)
- bufferevent_suspend_read(underlying,
+ bufferevent_suspend_read_(underlying,
BEV_SUSPEND_FILT_READ);
- } else {
- bev_ssl->bev.bev.enabled = EV_READ|EV_WRITE;
- if (bev_ssl->fd_is_set) {
- if (state != BUFFEREVENT_SSL_OPEN)
- if (event_add(&bev_ssl->bev.bev.ev_read, NULL) < 0)
- goto err;
- if (event_add(&bev_ssl->bev.bev.ev_write, NULL) < 0)
- goto err;
- }
}
return &bev_ssl->bev.bev;
@@ -1439,6 +1461,31 @@ bufferevent_openssl_socket_new(struct event_base *base,
base, NULL, fd, ssl, state, options);
}
+int
+bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev)
+{
+ int allow_dirty_shutdown = -1;
+ struct bufferevent_openssl *bev_ssl;
+ BEV_LOCK(bev);
+ bev_ssl = upcast(bev);
+ if (bev_ssl)
+ allow_dirty_shutdown = bev_ssl->allow_dirty_shutdown;
+ BEV_UNLOCK(bev);
+ return allow_dirty_shutdown;
+}
+
+void
+bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
+ int allow_dirty_shutdown)
+{
+ struct bufferevent_openssl *bev_ssl;
+ BEV_LOCK(bev);
+ bev_ssl = upcast(bev);
+ if (bev_ssl)
+ bev_ssl->allow_dirty_shutdown = !!allow_dirty_shutdown;
+ BEV_UNLOCK(bev);
+}
+
unsigned long
bufferevent_get_openssl_error(struct bufferevent *bev)
{