Subject: ssl: stop spinning on close
authorMartin Milata <martin@martinmilata.cz>
Thu, 6 Apr 2017 17:37:14 +0000 (19:37 +0200)
committerAndy Green <andy@warmcat.com>
Wed, 19 Apr 2017 12:49:44 +0000 (20:49 +0800)
lib/libwebsockets.c
lib/service.c

index 6917070..98b8df9 100755 (executable)
@@ -510,14 +510,28 @@ just_kill_connection:
            !wsi->socket_is_permanently_unusable) {
 #ifdef LWS_OPENSSL_SUPPORT
                if (lws_is_ssl(wsi) && wsi->ssl)
-               {
-                       lwsl_info("%s: shutting down SSL connection: %p (ssl %p, sock %d, state %d)\n", __func__, wsi, wsi->ssl, (int)(long)wsi->desc.sockfd, wsi->state);
+               {
+                       lwsl_info("%s: shutting down SSL connection: %p (ssl %p, sock %d, state %d)\n", __func__, wsi, wsi->ssl, (int)(long)wsi->desc.sockfd, wsi->state);
                        n = SSL_shutdown(wsi->ssl);
-                       if (n == 1) /* If finished the SSL shutdown, then do socket shutdown, else need to retry SSL shutdown */
-                               n = shutdown(wsi->desc.sockfd, SHUT_WR);
-                       else
-                               lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
-               }
+                       if (n == 1) /* If finished the SSL shutdown, then do socket shutdown, else need to retry SSL shutdown */
+                               n = shutdown(wsi->desc.sockfd, SHUT_WR);
+                       else if (n == 0)
+                               lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
+                       else /* n < 0 */
+                       {
+                               int shutdown_error = SSL_get_error(wsi->ssl, n);
+                               lwsl_debug("SSL_shutdown returned %d, SSL_get_error: %d\n", n, shutdown_error);
+                               if (shutdown_error == SSL_ERROR_WANT_READ) {
+                                       lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
+                                       n = 0;
+                               } else if (shutdown_error == SSL_ERROR_WANT_WRITE) {
+                                       lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLOUT);
+                                       n = 0;
+                               } else { // actual error occurred, just close the connection
+                                       n = shutdown(wsi->desc.sockfd, SHUT_WR);
+                               }
+                       }
+               }
                else
 #endif
                {
index 159dd8c..5d402d0 100644 (file)
@@ -911,22 +911,40 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
 
 
 #ifdef LWS_OPENSSL_SUPPORT
-       if ((wsi->state == LWSS_SHUTDOWN) && lws_is_ssl(wsi) && wsi->ssl)
-       {
-               n = SSL_shutdown(wsi->ssl);
-               lwsl_debug("SSH_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
-               if (n == 1)
-               {
-                       n = shutdown(wsi->desc.sockfd, SHUT_WR);
-                       goto close_and_handled;
-               }
-               else
-               {
-                       lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
-                       n = 0;
-                       goto handled;
-               }
-       }
+       if ((wsi->state == LWSS_SHUTDOWN) && lws_is_ssl(wsi) && wsi->ssl)
+       {
+               n = SSL_shutdown(wsi->ssl);
+               lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
+               if (n == 1)
+               {
+                       n = shutdown(wsi->desc.sockfd, SHUT_WR);
+                       goto close_and_handled;
+               }
+               else if (n == 0)
+               {
+                       lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
+                       n = 0;
+                       goto handled;
+               }
+               else /* n < 0 */
+               {
+                       int shutdown_error = SSL_get_error(wsi->ssl, n);
+                       lwsl_debug("SSL_shutdown returned %d, SSL_get_error: %d\n", n, shutdown_error);
+                       if (shutdown_error == SSL_ERROR_WANT_READ) {
+                               lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
+                               n = 0;
+                               goto handled;
+                       } else if (shutdown_error == SSL_ERROR_WANT_WRITE) {
+                               lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLOUT);
+                               n = 0;
+                               goto handled;
+                       }
+
+                       // actual error occurred, just close the connection
+                       n = shutdown(wsi->desc.sockfd, SHUT_WR);
+                       goto close_and_handled;
+               }
+       }
 #endif
 
        /* okay, what we came here to do... */