]> granicus.if.org Git - libevent/commitdiff
Fix reusing bufferevent_openssl after fd was reseted (i.e. on new connection)
authorAzat Khuzhin <a3at.mail@gmail.com>
Sat, 19 Nov 2016 14:08:53 +0000 (17:08 +0300)
committerAzat Khuzhin <a3at.mail@gmail.com>
Tue, 6 Dec 2016 22:34:14 +0000 (01:34 +0300)
For example if you trying to issue multiple requests over the same
evhttp_conneciton, and if connection already closed (IOW it should be
re-connected), than you will get into trouble since it will got wrong
openssl state. This patch addresses this issue by restoring state to
initial if SETFD called with -1 fd.

bufferevent_openssl.c

index 87225ca1218455e10a6bb84614524c8130b45818..fe057f0acb7c1cd265504310354cfe601de99bad 100644 (file)
@@ -323,6 +323,8 @@ struct bufferevent_openssl {
 
        /* Are we currently connecting, accepting, or doing IO? */
        unsigned state : 2;
+       /* If we reset fd, we sould reset state too */
+       unsigned old_state : 2;
 };
 
 static int be_openssl_enable(struct bufferevent *, short);
@@ -1004,12 +1006,6 @@ set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
                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)
@@ -1111,13 +1107,6 @@ set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
        }
 }
 
-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)
 {
@@ -1127,7 +1116,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_auto(bev_ssl, -1) < 0)
+       if (set_handshake_callbacks(bev_ssl, be_openssl_auto_fd(bev_ssl, -1)) < 0)
                return -1;
        if (!bev_ssl->underlying)
                return do_handshake(bev_ssl);
@@ -1262,6 +1251,34 @@ be_openssl_flush(struct bufferevent *bufev,
        return 0;
 }
 
+int
+be_openssl_set_fd(struct bufferevent_openssl *bev_ssl,
+    enum bufferevent_ssl_state state, int fd)
+{
+       bev_ssl->state = state;
+
+       switch (state) {
+       case BUFFEREVENT_SSL_ACCEPTING:
+               SSL_set_accept_state(bev_ssl->ssl);
+               if (set_handshake_callbacks(bev_ssl, fd) < 0)
+                       return -1;
+               break;
+       case BUFFEREVENT_SSL_CONNECTING:
+               SSL_set_connect_state(bev_ssl->ssl);
+               if (set_handshake_callbacks(bev_ssl, fd) < 0)
+                       return -1;
+               break;
+       case BUFFEREVENT_SSL_OPEN:
+               if (set_open_callbacks(bev_ssl, fd) < 0)
+                       return -1;
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
 static int
 be_openssl_ctrl(struct bufferevent *bev,
     enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
@@ -1276,11 +1293,8 @@ be_openssl_ctrl(struct bufferevent *bev,
                        bio = BIO_new_socket(data->fd, 0);
                        SSL_set_bio(bev_ssl->ssl, bio, bio);
                }
-               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);
-               }
+
+               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);
                return 0;
@@ -1344,29 +1358,14 @@ bufferevent_openssl_new_impl(struct event_base *base,
                bufferevent_incref_(underlying);
        }
 
-       bev_ssl->state = state;
+       bev_ssl->old_state = state;
        bev_ssl->last_write = -1;
 
        init_bio_counts(bev_ssl);
 
-       switch (state) {
-       case BUFFEREVENT_SSL_ACCEPTING:
-               SSL_set_accept_state(bev_ssl->ssl);
-               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_auto(bev_ssl, fd) < 0)
-                       goto err;
-               break;
-       case BUFFEREVENT_SSL_OPEN:
-               if (set_open_callbacks_auto(bev_ssl, fd) < 0)
-                       goto err;
-               break;
-       default:
+       fd = be_openssl_auto_fd(bev_ssl, fd);
+       if (be_openssl_set_fd(bev_ssl, state, fd))
                goto err;
-       }
 
        if (underlying) {
                bufferevent_setwatermark(underlying, EV_READ, 0, 0);