diff options
author | Azat Khuzhin <a3at.mail@gmail.com> | 2015-08-22 21:38:18 +0300 |
---|---|---|
committer | Azat Khuzhin <a3at.mail@gmail.com> | 2015-09-02 19:20:19 +0300 |
commit | 40b03798338b582b9ac467a1bc4b6e98b42d5396 (patch) | |
tree | 2ff77867c1837e4f1676dab05dfb0ffe32462e0f /bufferevent_openssl.c | |
parent | af85ecfccc82ef5f5ffaa33d778abdc795dbea5b (diff) | |
download | libevent-40b03798338b582b9ac467a1bc4b6e98b42d5396.tar.gz |
be_openssl: get rid off hackish "fd_is_set", to fix some corner cases
This patch is a cleanup and a bug fix, it drops ```fd_is_set``` flag, and
replace it with some checks to event_initialized(), and now we will not call
event_assign() on already added event, plus we will delete event when we really
have to (this patch fixes the case when server is down, IOW before this patch
we will not call event_del() because ```fd_is_set``` was reset to 0) and this
will fix some issues with retries in http layer for ssl.
Reported-in: #258
Fixes: regress ssl/bufferevent_socketpair_timeout
Fixes: regress ssl/bufferevent_socketpair_timeout_freed_fd
Diffstat (limited to 'bufferevent_openssl.c')
-rw-r--r-- | bufferevent_openssl.c | 71 |
1 files changed, 35 insertions, 36 deletions
diff --git a/bufferevent_openssl.c b/bufferevent_openssl.c index b30f90ff..2fdd193b 100644 --- a/bufferevent_openssl.c +++ b/bufferevent_openssl.c @@ -320,8 +320,6 @@ struct bufferevent_openssl { unsigned write_blocked_on_read : 1; /* 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; @@ -968,27 +966,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) { + int new_fd = fd < 0 ? event_get_fd(&bev->ev_read) : fd; + + if (fd >= 0 && 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, + + event_assign(&bev->ev_read, bev->ev_base, new_fd, EV_READ|EV_PERSIST|EV_FINALIZE, be_openssl_readeventcb, bev_ssl); - event_assign(&bev->ev_write, bev->ev_base, fd, + event_assign(&bev->ev_write, bev->ev_base, new_fd, EV_WRITE|EV_PERSIST|EV_FINALIZE, be_openssl_writeeventcb, bev_ssl); + if (rpending) 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; - } + return (r1<0 || r2<0) ? -1 : 0; } } @@ -1011,9 +1009,10 @@ 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); /* 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, @@ -1074,12 +1073,12 @@ set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd) } 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|EV_FINALIZE, be_openssl_handshakeeventcb, bev_ssl); @@ -1089,12 +1088,23 @@ set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd) 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; } } +static int +set_handshake_callbacks_auto(struct bufferevent_openssl *bev_ssl, evutil_socket_t 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 set_handshake_callbacks(bev_ssl, fd); +} + int bufferevent_ssl_renegotiate(struct bufferevent *bev) { @@ -1104,7 +1114,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_auto(bev_ssl, -1) < 0) return -1; if (!bev_ssl->underlying) return do_handshake(bev_ssl); @@ -1162,8 +1172,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); @@ -1274,25 +1282,16 @@ be_openssl_ctrl(struct bufferevent *bev, BIO *bio; bio = BIO_new_socket(data->fd, 0); SSL_set_bio(bev_ssl->ssl, bio, bio); - bev_ssl->fd_is_set = 1; } - if (data->fd == -1) - bev_ssl->fd_is_set = 0; if (bev_ssl->state == BUFFEREVENT_SSL_OPEN) return set_open_callbacks(bev_ssl, data->fd); else { return set_handshake_callbacks(bev_ssl, 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); 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: @@ -1360,12 +1359,12 @@ bufferevent_openssl_new_impl(struct event_base *base, switch (state) { case BUFFEREVENT_SSL_ACCEPTING: SSL_set_accept_state(bev_ssl->ssl); - if (set_handshake_callbacks(bev_ssl, fd) < 0) + if (set_handshake_callbacks_auto(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) + if (set_handshake_callbacks_auto(bev_ssl, fd) < 0) goto err; break; case BUFFEREVENT_SSL_OPEN: @@ -1383,14 +1382,14 @@ bufferevent_openssl_new_impl(struct event_base *base, 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) + struct bufferevent *bev = &bev_ssl->bev.bev; + bev->enabled = EV_READ|EV_WRITE; + if (state != BUFFEREVENT_SSL_OPEN) + if (event_add(&bev->ev_read, NULL) < 0) + goto err; + if (event_initialized(&bev->ev_write)) + if (event_add(&bev->ev_write, NULL) < 0) goto err; - } } return &bev_ssl->bev.bev; |