* 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;
int n;
int m;
char buf;
+ struct libwebsocket *wsi, *wsi_next;
/* stay dead once we are dead */
#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)
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;
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;
#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
#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;
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,
}
#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)
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) {
* 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);