Merge branch 'openssl-filter-fixes-v4'

* openssl-filter-fixes-v4:
  be: fix with filtered bufferevents and connect() without EAGAIN
  test/ssl: fix bufferevent_getfd() for bufferevent_openssl_filter_new()
  be_openssl: Fix writing into filted openssl bufferevent after connected
  test/https: separate cases for https client with filtered openssl bufferevent
  test/ssl: cover case when we writing to be_openssl after connecting

Fixes: #428
This commit is contained in:
Azat Khuzhin 2017-01-19 20:53:18 +03:00
commit 83e0f43b03
4 changed files with 78 additions and 38 deletions

View File

@ -404,7 +404,10 @@ start_writing(struct bufferevent_openssl *bev_ssl)
{ {
int r = 0; int r = 0;
if (bev_ssl->underlying) { if (bev_ssl->underlying) {
; if (bev_ssl->write_blocked_on_read) {
bufferevent_unsuspend_read_(bev_ssl->underlying,
BEV_SUSPEND_FILT_READ);
}
} else { } else {
struct bufferevent *bev = &bev_ssl->bev.bev; 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);
@ -435,7 +438,8 @@ stop_writing(struct bufferevent_openssl *bev_ssl)
if (bev_ssl->read_blocked_on_write) if (bev_ssl->read_blocked_on_write)
return; return;
if (bev_ssl->underlying) { if (bev_ssl->underlying) {
; bufferevent_unsuspend_read_(bev_ssl->underlying,
BEV_SUSPEND_FILT_READ);
} else { } else {
struct bufferevent *bev = &bev_ssl->bev.bev; struct bufferevent *bev = &bev_ssl->bev.bev;
event_del(&bev->ev_write); event_del(&bev->ev_write);
@ -716,7 +720,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost)
if (bev_ssl->underlying) if (bev_ssl->underlying)
BEV_RESET_GENERIC_WRITE_TIMEOUT(bev); BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
bufferevent_trigger_nolock_(bev, EV_WRITE, 0); bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
} }
return result; return result;
} }
@ -1040,17 +1044,11 @@ do_handshake(struct bufferevent_openssl *bev_ssl)
print_err(err); print_err(err);
switch (err) { switch (err) {
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
if (!bev_ssl->underlying) { stop_reading(bev_ssl);
stop_reading(bev_ssl); return start_writing(bev_ssl);
return start_writing(bev_ssl);
}
return 0;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
if (!bev_ssl->underlying) { stop_writing(bev_ssl);
stop_writing(bev_ssl); return start_reading(bev_ssl);
return start_reading(bev_ssl);
}
return 0;
default: default:
conn_closed(bev_ssl, BEV_EVENT_READING, err, r); conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
return -1; return -1;
@ -1086,6 +1084,13 @@ set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
be_openssl_handshakecb, be_openssl_handshakecb, be_openssl_handshakecb, be_openssl_handshakecb,
be_openssl_eventcb, be_openssl_eventcb,
bev_ssl); bev_ssl);
if (fd < 0)
return 0;
if (bufferevent_setfd(bev_ssl->underlying, fd))
return 1;
return do_handshake(bev_ssl); return do_handshake(bev_ssl);
} else { } else {
struct bufferevent *bev = &bev_ssl->bev.bev; struct bufferevent *bev = &bev_ssl->bev.bev;
@ -1131,10 +1136,13 @@ be_openssl_outbuf_cb(struct evbuffer *buf,
int r = 0; int r = 0;
/* XXX need to hold a reference here. */ /* XXX need to hold a reference here. */
if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN && if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN) {
cbinfo->orig_size == 0) { 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); &bev_ssl->bev.bev.timeout_write);
if (bev_ssl->underlying)
consider_writing(bev_ssl);
} }
/* XXX Handle r < 0 */ /* XXX Handle r < 0 */
(void)r; (void)r;
@ -1286,17 +1294,24 @@ be_openssl_ctrl(struct bufferevent *bev,
struct bufferevent_openssl *bev_ssl = upcast(bev); struct bufferevent_openssl *bev_ssl = upcast(bev);
switch (op) { switch (op) {
case BEV_CTRL_SET_FD: case BEV_CTRL_SET_FD:
if (bev_ssl->underlying) if (!bev_ssl->underlying) {
return -1;
{
BIO *bio; BIO *bio;
bio = BIO_new_socket(data->fd, 0); bio = BIO_new_socket(data->fd, 0);
SSL_set_bio(bev_ssl->ssl, bio, bio); SSL_set_bio(bev_ssl->ssl, bio, bio);
} 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); return be_openssl_set_fd(bev_ssl, bev_ssl->old_state, data->fd);
case BEV_CTRL_GET_FD: case BEV_CTRL_GET_FD:
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; return 0;
case BEV_CTRL_GET_UNDERLYING: case BEV_CTRL_GET_UNDERLYING:
data->ptr = bev_ssl->underlying; data->ptr = bev_ssl->underlying;

View File

@ -249,8 +249,8 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
/* we need to fake the error if the connection was refused /* we need to fake the error if the connection was refused
* immediately - usually connection to localhost on BSD */ * immediately - usually connection to localhost on BSD */
if (bufev_p->connection_refused) { if (bufev_p->connection_refused) {
bufev_p->connection_refused = 0; bufev_p->connection_refused = 0;
c = -1; c = -1;
} }
if (c == 0) if (c == 0)
@ -438,13 +438,12 @@ bufferevent_socket_connect(struct bufferevent *bev,
/* The connect succeeded already. How very BSD of it. */ /* The connect succeeded already. How very BSD of it. */
result = 0; result = 0;
bufev_p->connecting = 1; bufev_p->connecting = 1;
event_active(&bev->ev_write, EV_WRITE, 1); bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
} else { } else {
/* The connect failed already. How very BSD of it. */ /* The connect failed already. How very BSD of it. */
bufev_p->connection_refused = 1;
bufev_p->connecting = 1;
result = 0; result = 0;
event_active(&bev->ev_write, EV_WRITE, 1); bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS);
bufferevent_disable(bev, EV_WRITE|EV_READ);
} }
goto done; goto done;

View File

@ -85,6 +85,7 @@ static void http_on_complete_cb(struct evhttp_request *req, void *arg);
#define HTTP_BIND_IPV6 1 #define HTTP_BIND_IPV6 1
#define HTTP_BIND_SSL 2 #define HTTP_BIND_SSL 2
#define HTTP_SSL_FILTER 4
static int static int
http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask) http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask)
{ {
@ -424,18 +425,25 @@ http_complete_write(evutil_socket_t fd, short what, void *arg)
} }
static struct bufferevent * static struct bufferevent *
create_bev(struct event_base *base, int fd, int ssl) create_bev(struct event_base *base, int fd, int ssl_mask)
{ {
int flags = BEV_OPT_DEFER_CALLBACKS; int flags = BEV_OPT_DEFER_CALLBACKS;
struct bufferevent *bev = NULL; struct bufferevent *bev = NULL;
if (!ssl) { if (!ssl_mask) {
bev = bufferevent_socket_new(base, fd, flags); bev = bufferevent_socket_new(base, fd, flags);
} else { } else {
#ifdef EVENT__HAVE_OPENSSL #ifdef EVENT__HAVE_OPENSSL
SSL *ssl = SSL_new(get_ssl_ctx()); SSL *ssl = SSL_new(get_ssl_ctx());
bev = bufferevent_openssl_socket_new( if (ssl_mask & HTTP_SSL_FILTER) {
base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags); struct bufferevent *underlying =
bufferevent_socket_new(base, fd, flags);
bev = bufferevent_openssl_filter_new(
base, underlying, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
} else {
bev = bufferevent_openssl_socket_new(
base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
}
bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
#endif #endif
} }
@ -4519,6 +4527,8 @@ http_request_own_test(void *arg)
#ifdef EVENT__HAVE_OPENSSL #ifdef EVENT__HAVE_OPENSSL
static void https_basic_test(void *arg) static void https_basic_test(void *arg)
{ return http_basic_test_impl(arg, 1); } { return http_basic_test_impl(arg, 1); }
static void https_filter_basic_test(void *arg)
{ return http_basic_test_impl(arg, 1 | HTTP_SSL_FILTER); }
static void https_incomplete_test(void *arg) static void https_incomplete_test(void *arg)
{ http_incomplete_test_(arg, 0, 1); } { http_incomplete_test_(arg, 0, 1); }
static void https_incomplete_timeout_test(void *arg) static void https_incomplete_timeout_test(void *arg)
@ -4533,6 +4543,8 @@ static void https_connection_retry_test(void *arg)
{ return http_connection_retry_test_impl(arg, 1); } { return http_connection_retry_test_impl(arg, 1); }
static void https_chunk_out_test(void *arg) static void https_chunk_out_test(void *arg)
{ return http_chunk_out_test_impl(arg, 1); } { return http_chunk_out_test_impl(arg, 1); }
static void https_filter_chunk_out_test(void *arg)
{ return http_chunk_out_test_impl(arg, 1 | HTTP_SSL_FILTER); }
static void https_stream_out_test(void *arg) static void https_stream_out_test(void *arg)
{ return http_stream_out_test_impl(arg, 1); } { return http_stream_out_test_impl(arg, 1); }
static void https_connection_fail_test(void *arg) static void https_connection_fail_test(void *arg)
@ -4620,6 +4632,7 @@ struct testcase_t http_testcases[] = {
#ifdef EVENT__HAVE_OPENSSL #ifdef EVENT__HAVE_OPENSSL
HTTPS(basic), HTTPS(basic),
HTTPS(filter_basic),
HTTPS(simple), HTTPS(simple),
HTTPS(simple_dirty), HTTPS(simple_dirty),
HTTPS(incomplete), HTTPS(incomplete),
@ -4628,6 +4641,7 @@ struct testcase_t http_testcases[] = {
{ "https_connection_retry_conn_address", https_connection_retry_conn_address_test, { "https_connection_retry_conn_address", https_connection_retry_conn_address_test,
TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL }, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
HTTPS(chunk_out), HTTPS(chunk_out),
HTTPS(filter_chunk_out),
HTTPS(stream_out), HTTPS(stream_out),
HTTPS(connection_fail), HTTPS(connection_fail),
HTTPS(write_during_read), HTTPS(write_during_read),

View File

@ -227,19 +227,20 @@ enum regress_openssl_type
REGRESS_OPENSSL_FREED = 256, REGRESS_OPENSSL_FREED = 256,
REGRESS_OPENSSL_TIMEOUT = 512, REGRESS_OPENSSL_TIMEOUT = 512,
REGRESS_OPENSSL_SLEEP = 1024, REGRESS_OPENSSL_SLEEP = 1024,
REGRESS_OPENSSL_CLIENT_WRITE = 2048,
}; };
static void static void
bufferevent_openssl_check_fd(struct bufferevent *bev, int filter) bufferevent_openssl_check_fd(struct bufferevent *bev, int filter)
{ {
tt_int_op(bufferevent_getfd(bev), !=, -1);
tt_int_op(bufferevent_setfd(bev, -1), ==, 0);
if (filter) { if (filter) {
tt_int_op(bufferevent_getfd(bev), ==, -1);
tt_int_op(bufferevent_setfd(bev, -1), ==, -1);
} else {
tt_int_op(bufferevent_getfd(bev), !=, -1); tt_int_op(bufferevent_getfd(bev), !=, -1);
tt_int_op(bufferevent_setfd(bev, -1), ==, 0); } else {
tt_int_op(bufferevent_getfd(bev), ==, -1);
} }
tt_int_op(bufferevent_getfd(bev), ==, -1);
end: end:
; ;
@ -322,6 +323,9 @@ eventcb(struct bufferevent *bev, short what, void *ctx)
if (--pending_connect_events == 0) if (--pending_connect_events == 0)
event_base_loopexit(exit_base, NULL); event_base_loopexit(exit_base, NULL);
} }
if ((type & REGRESS_OPENSSL_CLIENT_WRITE) && (type & REGRESS_OPENSSL_CLIENT))
evbuffer_add_printf(bufferevent_get_output(bev), "1\n");
} else if (what & BEV_EVENT_EOF) { } else if (what & BEV_EVENT_EOF) {
TT_BLATHER(("Got a good EOF")); TT_BLATHER(("Got a good EOF"));
++got_close; ++got_close;
@ -465,7 +469,8 @@ regress_bufferevent_openssl(void *arg)
bufferevent_enable(bev1, EV_READ|EV_WRITE); bufferevent_enable(bev1, EV_READ|EV_WRITE);
bufferevent_enable(bev2, EV_READ|EV_WRITE); bufferevent_enable(bev2, EV_READ|EV_WRITE);
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n"); if (!(type & REGRESS_OPENSSL_CLIENT_WRITE))
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
event_base_dispatch(data->base); event_base_dispatch(data->base);
@ -488,7 +493,8 @@ regress_bufferevent_openssl(void *arg)
bufferevent_set_timeouts(bev1, &t, &t); bufferevent_set_timeouts(bev1, &t, &t);
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n"); if (!(type & REGRESS_OPENSSL_CLIENT_WRITE))
evbuffer_add_printf(bufferevent_get_output(bev1), "1\n");
event_base_dispatch(data->base); event_base_dispatch(data->base);
@ -731,8 +737,14 @@ struct testcase_t ssl_testcases[] = {
#define T(a) ((void *)(a)) #define T(a) ((void *)(a))
{ "bufferevent_socketpair", regress_bufferevent_openssl, { "bufferevent_socketpair", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_SOCKETPAIR) }, TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_SOCKETPAIR) },
{ "bufferevent_socketpair_write_after_connect", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR|REGRESS_OPENSSL_CLIENT_WRITE) },
{ "bufferevent_filter", regress_bufferevent_openssl, { "bufferevent_filter", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_FILTER) }, TT_ISOLATED, &basic_setup, T(REGRESS_OPENSSL_FILTER) },
{ "bufferevent_filter_write_after_connect", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_FILTER|REGRESS_OPENSSL_CLIENT_WRITE) },
{ "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl, { "bufferevent_renegotiate_socketpair", regress_bufferevent_openssl,
TT_ISOLATED, &basic_setup, TT_ISOLATED, &basic_setup,
T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) }, T(REGRESS_OPENSSL_SOCKETPAIR | REGRESS_OPENSSL_RENEGOTIATE) },