Merge branch 'be-openssl-drop-fd_is_set-v4'

This must fix some issues with bufferevent openssl layer + some cleanups.

* be-openssl-drop-fd_is_set-v4:
  be_openssl: don't use *_auto() in do_handshake() we can't have fd == -1 there
  be_openssl: don't call set_open_callbacks() if fd == -1
  be_openssl: introduce be_openssl_auto_fd() helper
  be_openssl: introduce set_open_callbacks_auto()
  be_openssl: get rid off hackish "fd_is_set", to fix some corner cases
This commit is contained in:
Azat Khuzhin 2015-09-02 19:34:15 +03:00
commit 620aae969c

View File

@ -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;
@ -957,6 +955,18 @@ be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
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
set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
{
@ -968,30 +978,36 @@ 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|EV_FINALIZE,
be_openssl_readeventcb, bev_ssl);
event_assign(&bev->ev_write, bev->ev_base, 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;
}
}
static int
set_open_callbacks_auto(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
{
fd = be_openssl_auto_fd(bev_ssl, fd);
return set_open_callbacks(bev_ssl, fd);
}
static int
do_handshake(struct bufferevent_openssl *bev_ssl)
@ -1011,9 +1027,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 +1091,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 +1106,18 @@ 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)
{
fd = be_openssl_auto_fd(bev_ssl, fd);
return set_handshake_callbacks(bev_ssl, fd);
}
int
bufferevent_ssl_renegotiate(struct bufferevent *bev)
{
@ -1104,7 +1127,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 +1185,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 +1295,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)
if (bev_ssl->state == BUFFEREVENT_SSL_OPEN && data->fd >= 0)
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,16 +1372,16 @@ 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:
if (set_open_callbacks(bev_ssl, fd) < 0)
if (set_open_callbacks_auto(bev_ssl, fd) < 0)
goto err;
break;
default:
@ -1383,14 +1395,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;