From: Azat Khuzhin <a3at.mail@gmail.com> Date: Tue, 6 Dec 2016 23:53:07 +0000 (+0300) Subject: be_openssl: Fix writing into filted openssl bufferevent after connected X-Git-Tag: release-2.1.8-stable~5^2~2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8939676706b8e2a125c5e3344f8672ddfadeb4e1;p=libevent be_openssl: Fix writing into filted openssl bufferevent after connected The main problems was due to when bufferevent_openssl has underlying (i.e. created with bufferevent_openssl_filter_new()) some events was disabled/suspended, while with openssl, READ can require WRITE and vice-versa hence this issues. The BEV_CTRL_GET_FD hunk to fix http subsystem, since it depends from what bufferevent_getfd() returns. Fixes: #428 Fixes: ssl/bufferevent_filter_write_after_connect Fixes: http/https_filter_chunk_out Fixes: da52933550fd4736aa1c213b6de497e2ffc31e34 ("be_openssl: don't call do_write() directly from outbuf_cb") --- diff --git a/bufferevent_openssl.c b/bufferevent_openssl.c index cbb7f8a5..da3963af 100644 --- a/bufferevent_openssl.c +++ b/bufferevent_openssl.c @@ -404,7 +404,10 @@ 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); @@ -435,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); @@ -716,7 +720,7 @@ do_write(struct bufferevent_openssl *bev_ssl, int atmost) if (bev_ssl->underlying) 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; } @@ -1040,17 +1044,11 @@ do_handshake(struct bufferevent_openssl *bev_ssl) 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, BEV_EVENT_READING, err, r); 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_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; @@ -1131,10 +1136,13 @@ be_openssl_outbuf_cb(struct evbuffer *buf, int r = 0; /* XXX need to hold a reference here. */ - if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN && - cbinfo->orig_size == 0) { - r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write, - &bev_ssl->bev.bev.timeout_write); + 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, + &bev_ssl->bev.bev.timeout_write); + + if (bev_ssl->underlying) + consider_writing(bev_ssl); } /* XXX Handle r < 0 */ (void)r; @@ -1286,17 +1294,24 @@ be_openssl_ctrl(struct bufferevent *bev, 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); + } 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: - 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: data->ptr = bev_ssl->underlying;