1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-16 00:00:07 +01:00

ssl pending buffered reads use linked list

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2015-01-29 08:36:18 +08:00
parent 7e37d10e47
commit 5281560000
4 changed files with 74 additions and 34 deletions

View file

@ -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;

View file

@ -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;
}
#ifdef LWS_OPENSSL_SUPPORT
/*
* 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++) {
#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;
}
#endif
if (!context->fds[n].revents)
continue;

View file

@ -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,

View file

@ -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);