From 528156000092b1a441f2d45b838b254d430fce21 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Thu, 29 Jan 2015 08:36:18 +0800 Subject: [PATCH] ssl pending buffered reads use linked list Signed-off-by: Andy Green --- lib/libwebsockets.c | 2 ++ lib/lws-plat-unix.c | 57 ++++++++++++++++++++++++--------------------- lib/private-libwebsockets.h | 11 +++++++-- lib/ssl.c | 38 ++++++++++++++++++++++++++---- 4 files changed, 74 insertions(+), 34 deletions(-) diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 2295cc0..1d8af8d 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -209,6 +209,8 @@ just_kill_connection: * delete socket from the internal poll list if still present */ + lws_ssl_remove_wsi_from_buffered_list(context, wsi); + remove_wsi_socket_from_fds(context, wsi); wsi->state = WSI_STATE_DEAD_SOCKET; diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c index 1b83187..a894e80 100644 --- a/lib/lws-plat-unix.c +++ b/lib/lws-plat-unix.c @@ -97,6 +97,7 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) int n; int m; char buf; + struct libwebsocket *wsi, *wsi_next; /* stay dead once we are dead */ @@ -110,25 +111,20 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) #ifdef LWS_OPENSSL_SUPPORT /* if we know we have non-network pending data, do not wait in poll */ - if (context->ssl_flag_buffered_reads) + if (lws_ssl_anybody_has_buffered_read(context)) timeout_ms = 0; #endif n = poll(context->fds, context->fds_count, timeout_ms); context->service_tid = 0; #ifdef LWS_OPENSSL_SUPPORT - if (!context->ssl_flag_buffered_reads && n == 0) { + if (!lws_ssl_anybody_has_buffered_read(context) && n == 0) { #else if (n == 0) /* poll timeout */ { #endif libwebsocket_service_fd(context, NULL); return 0; } - -#ifdef LWS_OPENSSL_SUPPORT - /* any more will have to set it fresh this time around */ - context->ssl_flag_buffered_reads = 0; -#endif if (n < 0) { if (LWS_ERRNO != LWS_EINTR) @@ -136,29 +132,36 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) return 0; } - /* 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; - if (context->fds[n].revents & POLLIN) - wsi->buffered_reads_pending = 0; - else - /* somebody left with pending SSL read data */ - context->ssl_flag_buffered_reads = 1; + /* + * For all guys with buffered SSL read data already saved up, if they + * are not flowcontrolled, fake their POLLIN status so they'll get + * service to use up the buffered incoming data, even though their + * network socket may have nothing + */ + + wsi = context->pending_read_list; + while (wsi) { + wsi_next = wsi->pending_read_list_next; + context->fds[wsi->sock].revents |= + context->fds[wsi->sock].events & POLLIN; + if (context->fds[wsi->sock].revents & POLLIN) { + /* + * he's going to get serviced now, take him off the + * list of guys with buffered SSL. If he still has some + * at the end of the service, he'll get put back on the + * list then. + */ + lws_ssl_remove_wsi_from_buffered_list(context, wsi); } + wsi = wsi_next; + } #endif + + /* any socket with events to service? */ + + for (n = 0; n < context->fds_count; n++) { + if (!context->fds[n].revents) continue; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 9c76070..34667b4 100755 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -474,7 +474,10 @@ struct libwebsocket_context { unsigned int user_supplied_ssl_ctx:1; SSL_CTX *ssl_ctx; SSL_CTX *ssl_client_ctx; - unsigned int ssl_flag_buffered_reads:1; + struct libwebsocket *pending_read_list; /* linked list */ +#define lws_ssl_anybody_has_buffered_read(ctx) (ctx->use_ssl && ctx->pending_read_list) +#else +#define lws_ssl_anybody_has_buffered_read(ctx) (0) #endif struct libwebsocket_protocols *protocols; int count_protocols; @@ -840,8 +843,8 @@ struct libwebsocket { #ifdef LWS_OPENSSL_SUPPORT SSL *ssl; BIO *client_bio; + struct libwebsocket *pending_read_list_prev, *pending_read_list_next; unsigned int use_ssl:2; - unsigned int buffered_reads_pending:1; unsigned int upgraded:1; #endif @@ -1089,6 +1092,7 @@ enum lws_ssl_capable_status { #define lws_server_socket_service_ssl(_a, _b, _c, _d, _e) (0) #define lws_ssl_close(_a) (0) #define lws_ssl_context_destroy(_a) +#define lws_ssl_remove_wsi_from_buffered_list(_a, _b) #else #define LWS_SSL_ENABLED(context) (context->use_ssl) LWS_EXTERN int openssl_websocket_private_data_index; @@ -1106,6 +1110,9 @@ LWS_EXTERN int lws_ssl_close(struct libwebsocket *wsi); LWS_EXTERN void lws_ssl_context_destroy(struct libwebsocket_context *context); +LWS_VISIBLE void +lws_ssl_remove_wsi_from_buffered_list(struct libwebsocket_context *context, + struct libwebsocket *wsi); #ifndef LWS_NO_SERVER LWS_EXTERN int lws_context_init_server_ssl(struct lws_context_creation_info *info, diff --git a/lib/ssl.c b/lib/ssl.c index a6be4fb..19d7333 100644 --- a/lib/ssl.c +++ b/lib/ssl.c @@ -392,6 +392,32 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, } #endif +LWS_VISIBLE void +lws_ssl_remove_wsi_from_buffered_list(struct libwebsocket_context *context, + struct libwebsocket *wsi) +{ + if (!wsi->pending_read_list_prev && + !wsi->pending_read_list_next && + context->pending_read_list != wsi) + /* we are not on the list */ + return; + + /* point previous guy's next to our next */ + if (!wsi->pending_read_list_prev) + context->pending_read_list = wsi->pending_read_list_next; + else + wsi->pending_read_list_prev->pending_read_list_next = + wsi->pending_read_list_next; + + /* point next guy's previous to our previous */ + if (wsi->pending_read_list_next) + wsi->pending_read_list_next->pending_read_list_prev = + wsi->pending_read_list_prev; + + wsi->pending_read_list_prev = NULL; + wsi->pending_read_list_next = NULL; +} + LWS_VISIBLE int lws_ssl_capable_read(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char *buf, int len) @@ -400,8 +426,6 @@ lws_ssl_capable_read(struct libwebsocket_context *context, if (!wsi->ssl) return lws_ssl_capable_read_no_ssl(context, wsi, buf, len); - - wsi->buffered_reads_pending = 0; n = SSL_read(wsi->ssl, buf, len); if (n >= 0) { @@ -413,10 +437,14 @@ lws_ssl_capable_read(struct libwebsocket_context *context, * and if we don't realize, this data will sit there forever */ if (n == len && wsi->ssl && SSL_pending(wsi->ssl)) { - context->ssl_flag_buffered_reads = 1; - wsi->buffered_reads_pending = 1; + assert(!wsi->pending_read_list_next && !wsi->pending_read_list_prev); + /* add us to the linked list of guys with pending ssl */ + context->pending_read_list->pending_read_list_prev = wsi; + wsi->pending_read_list_next = context->pending_read_list; + wsi->pending_read_list_prev = NULL; + context->pending_read_list = wsi; } - + return n; } n = SSL_get_error(wsi->ssl, n); -- 2.7.4