LWS_VISIBLE int lws_ssl_capable_read(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char *buf, int len) { int n; 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) { /* * 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)) { context->ssl_flag_buffered_reads = 1; 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; return LWS_SSL_CAPABLE_ERROR; }
LWS_VISIBLE int lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n; if (!wsi->ssl) return lws_ssl_capable_read_no_ssl(wsi, buf, len); n = SSL_read(wsi->ssl, buf, len); /* manpage: returning 0 means connection shut down */ if (!n) return LWS_SSL_CAPABLE_ERROR; if (n < 0) { n = SSL_get_error(wsi->ssl, n); if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) return LWS_SSL_CAPABLE_MORE_SERVICE; return LWS_SSL_CAPABLE_ERROR; } /* * 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) goto bail; if (!wsi->ssl) goto bail; if (!SSL_pending(wsi->ssl)) goto bail; if (wsi->pending_read_list_next) return n; if (wsi->pending_read_list_prev) return n; if (pt->pending_read_list == wsi) return n; /* add us to the linked list of guys with pending ssl */ if (pt->pending_read_list) pt->pending_read_list->pending_read_list_prev = wsi; wsi->pending_read_list_next = pt->pending_read_list; wsi->pending_read_list_prev = NULL; pt->pending_read_list = wsi; return n; bail: lws_ssl_remove_wsi_from_buffered_list(wsi); return n; }
LWS_VISIBLE int lws_ssl_capable_read(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char *buf, int len) { int n; if (!wsi->ssl) return lws_ssl_capable_read_no_ssl(context, wsi, buf, len); n = SSL_read(wsi->ssl, buf, len); 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)) { if (!wsi->pending_read_list_next && !wsi->pending_read_list_prev) { if (context->pending_read_list != wsi) { /* add us to the linked list of guys with pending ssl */ if (context->pending_read_list) 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; } } } else lws_ssl_remove_wsi_from_buffered_list(context, wsi); 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; return LWS_SSL_CAPABLE_ERROR; }
LWS_VISIBLE int lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n = 0, m; if (!wsi->ssl) return lws_ssl_capable_read_no_ssl(wsi, buf, len); lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1); errno = 0; n = SSL_read(wsi->ssl, buf, len); #if defined(LWS_WITH_ESP32) if (!n && errno == ENOTCONN) { lwsl_debug("%p: SSL_read ENOTCONN\n", wsi); return LWS_SSL_CAPABLE_ERROR; } #endif #if defined(LWS_WITH_STATS) if (!wsi->seen_rx) { lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_RX_DELAY, time_in_microseconds() - wsi->accept_start_us); lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1); wsi->seen_rx = 1; } #endif lwsl_debug("%p: SSL_read says %d\n", wsi, n); /* manpage: returning 0 means connection shut down */ if (!n || (n == -1 && errno == ENOTCONN)) { wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; } if (n < 0) { m = lws_ssl_get_error(wsi, n); lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno); if (m == SSL_ERROR_ZERO_RETURN || m == SSL_ERROR_SYSCALL) return LWS_SSL_CAPABLE_ERROR; if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) { lwsl_debug("%s: WANT_READ\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; } lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n); if (wsi->vhost) wsi->vhost->conn_stats.rx += n; lws_restart_ws_ping_pong_timer(wsi); /* * 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) goto bail; if (!wsi->ssl) goto bail; if (!SSL_pending(wsi->ssl)) goto bail; if (wsi->pending_read_list_next) return n; if (wsi->pending_read_list_prev) return n; if (pt->pending_read_list == wsi) return n; /* add us to the linked list of guys with pending ssl */ if (pt->pending_read_list) pt->pending_read_list->pending_read_list_prev = wsi; wsi->pending_read_list_next = pt->pending_read_list; wsi->pending_read_list_prev = NULL; pt->pending_read_list = wsi; return n; bail: lws_ssl_remove_wsi_from_buffered_list(wsi); return n; }
LWS_VISIBLE int lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n = 0, m; if (!wsi->tls.ssl) return lws_ssl_capable_read_no_ssl(wsi, buf, len); lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1); errno = 0; n = SSL_read(wsi->tls.ssl, buf, len); #if defined(LWS_WITH_ESP32) if (!n && errno == LWS_ENOTCONN) { lwsl_debug("%p: SSL_read ENOTCONN\n", wsi); return LWS_SSL_CAPABLE_ERROR; } #endif #if defined(LWS_WITH_STATS) if (!wsi->seen_rx && wsi->accept_start_us) { lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_RX_DELAY, lws_time_in_microseconds() - wsi->accept_start_us); lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1); wsi->seen_rx = 1; } #endif lwsl_debug("%p: SSL_read says %d\n", wsi, n); /* manpage: returning 0 means connection shut down * * 2018-09-10: https://github.com/openssl/openssl/issues/1903 * * So, in summary, if you get a 0 or -1 return from SSL_read() / * SSL_write(), you should call SSL_get_error(): * * - If you get back SSL_ERROR_RETURN_ZERO then you know the connection * has been cleanly shutdown by the peer. To fully close the * connection you may choose to call SSL_shutdown() to send a * close_notify back. * * - If you get back SSL_ERROR_SSL then some kind of internal or * protocol error has occurred. More details will be on the SSL error * queue. You can also call SSL_get_shutdown(). If this indicates a * state of SSL_RECEIVED_SHUTDOWN then you know a fatal alert has * been received from the peer (if it had been a close_notify then * SSL_get_error() would have returned SSL_ERROR_RETURN_ZERO). * SSL_ERROR_SSL is considered fatal - you should not call * SSL_shutdown() in this case. * * - If you get back SSL_ERROR_SYSCALL then some kind of fatal (i.e. * non-retryable) error has occurred in a system call. */ if (n <= 0) { m = lws_ssl_get_error(wsi, n); lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno); if (m == SSL_ERROR_ZERO_RETURN) /* cleanly shut down */ return LWS_SSL_CAPABLE_ERROR; /* hm not retryable.. could be 0 size pkt or error */ if (m == SSL_ERROR_SSL || m == SSL_ERROR_SYSCALL || errno == LWS_ENOTCONN) { /* unclean, eg closed conn */ wsi->socket_is_permanently_unusable = 1; return LWS_SSL_CAPABLE_ERROR; } /* retryable? */ if (SSL_want_read(wsi->tls.ssl)) { lwsl_debug("%s: WANT_READ\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } if (SSL_want_write(wsi->tls.ssl)) { lwsl_debug("%s: WANT_WRITE\n", __func__); lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } /* keep on trucking it seems */ } lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n); if (wsi->vhost) wsi->vhost->conn_stats.rx += n; // lwsl_hexdump_err(buf, n); /* * 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) goto bail; if (!wsi->tls.ssl) goto bail; if (!SSL_pending(wsi->tls.ssl)) goto bail; if (wsi->tls.pending_read_list_next) return n; if (wsi->tls.pending_read_list_prev) return n; if (pt->tls.pending_read_list == wsi) return n; /* add us to the linked list of guys with pending ssl */ if (pt->tls.pending_read_list) pt->tls.pending_read_list->tls.pending_read_list_prev = wsi; wsi->tls.pending_read_list_next = pt->tls.pending_read_list; wsi->tls.pending_read_list_prev = NULL; pt->tls.pending_read_list = wsi; return n; bail: lws_ssl_remove_wsi_from_buffered_list(wsi); return n; }