diff options
author | Azat Khuzhin <a3at.mail@gmail.com> | 2016-12-07 02:53:07 +0300 |
---|---|---|
committer | Azat Khuzhin <a3at.mail@gmail.com> | 2017-01-19 20:53:05 +0300 |
commit | 8939676706b8e2a125c5e3344f8672ddfadeb4e1 (patch) | |
tree | ed992f9150d6acb56f0ea3d5b9fa581b2818b400 /bufferevent_openssl.c | |
parent | d77fcea15fe8ebb166853597cfff934fd5a47b0f (diff) | |
download | libevent-8939676706b8e2a125c5e3344f8672ddfadeb4e1.tar.gz |
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")
Diffstat (limited to 'bufferevent_openssl.c')
-rw-r--r-- | bufferevent_openssl.c | 57 |
1 files changed, 36 insertions, 21 deletions
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; |