ssl fix pending reads stuck in ssl layer
authorAndy Green <andy.green@linaro.org>
Wed, 8 Oct 2014 03:29:49 +0000 (11:29 +0800)
committerAndy Green <andy.green@linaro.org>
Wed, 8 Oct 2014 04:15:29 +0000 (12:15 +0800)
Signed-off-by: Andy Green <andy.green@linaro.org>
lib/lws-plat-unix.c
lib/private-libwebsockets.h
lib/service.c
lib/ssl.c

index 71a988c..b8f209d 100644 (file)
@@ -125,6 +125,21 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
        /* any socket with events to service? */
 
        for (n = 0; n < context->fds_count; n++) {
+#ifdef LWS_OPENSSL_SUPPORT
+               struct libwebsocket *wsi;
+               
+               wsi = context->lws_lookup[context->fds[n].fd];
+               if (wsi == NULL)
+                       continue;
+               /* 
+                * if he's not flowcontrolled, make sure we service ssl
+                * pending read data
+                */
+               if (wsi->ssl && wsi->buffered_reads_pending) {
+                       lwsl_debug("wsi %p: forcing POLLIN\n", wsi);
+                       context->fds[n].revents |= context->fds[n].events & POLLIN;
+               }
+#endif
                if (!context->fds[n].revents)
                        continue;
 
index 3ec5d02..9f9c63a 100755 (executable)
@@ -747,6 +747,7 @@ struct libwebsocket {
        SSL *ssl;
        BIO *client_bio;
        unsigned int use_ssl:2;
+       unsigned int buffered_reads_pending:1;
 #endif
 
 #ifdef _WIN32
@@ -950,7 +951,6 @@ enum lws_ssl_capable_status {
 #define lws_context_init_server_ssl(_a, _b) (0)
 #define lws_ssl_destroy(_a)
 #define lws_context_init_http2_ssl(_a)
-#define lws_ssl_pending(_a) (0)
 #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl
 #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl
 #define lws_server_socket_service_ssl(_a, _b, _c, _d, _e) (0)
@@ -958,7 +958,6 @@ enum lws_ssl_capable_status {
 #define lws_ssl_context_destroy(_a)
 #else
 #define LWS_SSL_ENABLED(context) (context->use_ssl)
-LWS_EXTERN int lws_ssl_pending(struct libwebsocket *wsi);
 LWS_EXTERN int openssl_websocket_private_data_index;
 LWS_EXTERN int
 lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len);
index 9ab0ea1..a914e34 100644 (file)
@@ -436,7 +436,6 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                if (!(pollfd->revents & LWS_POLLIN))
                        break;
 
-read_pending:
                eff_buf.token_len = lws_ssl_capable_read(wsi,
                                context->service_buffer,
                                               sizeof(context->service_buffer));
@@ -505,8 +504,6 @@ drain:
                        n = _libwebsocket_rx_flow_control(wsi); /* n ignored, needed for NO_SERVER case */
                }
 
-               if (lws_ssl_pending(wsi))
-                       goto read_pending;
                break;
 
        default:
index 3a2a2db..89935f9 100644 (file)
--- a/lib/ssl.c
+++ b/lib/ssl.c
@@ -361,11 +361,23 @@ lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len)
 
        if (!wsi->ssl)
                return lws_ssl_capable_read_no_ssl(wsi, buf, len);
+       
+       wsi->buffered_reads_pending = 0;
 
        n = SSL_read(wsi->ssl, buf, len);
-       if (n >= 0)
+       if (n >= 0) {
+               /* 
+                * if it was our buffer that limited what we read,
+                * check if SSL has additional data pending inside SSL buffers.
+                * 
+                * Because these won't signal at the network layer with POLLIN
+                * and if we don't realize, this data will sit there forever
+                */
+               if (n == len && wsi->ssl && SSL_pending(wsi->ssl))
+                       wsi->buffered_reads_pending = 1;
+               
                return n;
-
+       }
        n = SSL_get_error(wsi->ssl, n);
        if (n ==  SSL_ERROR_WANT_READ || n ==  SSL_ERROR_WANT_WRITE)
                return LWS_SSL_CAPABLE_MORE_SERVICE;
@@ -396,14 +408,6 @@ lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len)
 }
 
 LWS_VISIBLE int
-lws_ssl_pending(struct libwebsocket *wsi)
-{
-       if (wsi->ssl)
-               return SSL_pending(wsi->ssl);
-       return 0;
-}
-
-LWS_VISIBLE int
 lws_ssl_close(struct libwebsocket *wsi)
 {
        int n;