diff --git a/lib/core-net/service.c b/lib/core-net/service.c index e00bc3717..62a73a4a1 100644 --- a/lib/core-net/service.c +++ b/lib/core-net/service.c @@ -68,6 +68,9 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) // lwsl_notice("%s: %s\n", __func__, lws_wsi_tag(wsi)); + if (wsi->socket_is_permanently_unusable) + return 0; + vwsi->leave_pollout_active = 0; vwsi->handling_pollout = 1; /* @@ -685,19 +688,39 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, * zero down pollfd->revents after handling */ - /* handle session socket closed */ + /* + * Whatever the situation with buffered rx packets, or explicitly read- + * and-buffered rx going to be handled before we want to acknowledge the + * socket is gone, any sign of HUP always immediately means no more tx + * is possible. + */ - if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) && - (pollfd->revents & LWS_POLLHUP)) { + if (pollfd->revents & LWS_POLLHUP) { + wsi->socket_is_permanently_unusable = 1; + + if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) { + + /* ... there are no pending rx packets waiting... */ + + if (!lws_buflist_total_len(&wsi->buflist)) { + + /* + * ... nothing stashed in the buflist either, + * so acknowledge the wsi is done + */ + + lwsl_debug("Session Socket %s (fd=%d) dead\n", + lws_wsi_tag(wsi), pollfd->fd); + + goto close_and_handled; + } + + /* + * ... in fact we have some unread rx buffered in the + * input buflist. Hold off the closing a bit... + */ - if (lws_buflist_total_len(&wsi->buflist)) lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 3); - else { - wsi->socket_is_permanently_unusable = 1; - lwsl_debug("Session Socket %s (fd=%d) dead\n", - lws_wsi_tag(wsi), pollfd->fd); - - goto close_and_handled; } } diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index ebe340817..ea69163f4 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -601,28 +601,6 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi, } #endif -#if 0 - - /* - * !!! lws_serve_http_file_fragment() seems to duplicate most of - * lws_handle_POLLOUT_event() in its own loop... - */ - lwsl_debug("%s: %d %d\n", __func__, (pollfd->revents & LWS_POLLOUT), - lwsi_state_can_handle_POLLOUT(wsi)); - - if ((pollfd->revents & LWS_POLLOUT) && - lwsi_state_can_handle_POLLOUT(wsi) && - lws_handle_POLLOUT_event(wsi, pollfd)) { - if (lwsi_state(wsi) == LRS_RETURNED_CLOSE) - lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE); - /* the write failed... it's had it */ - wsi->socket_is_permanently_unusable = 1; - - return LWS_HPI_RET_PLEASE_CLOSE_ME; - } -#endif - - /* Priority 2: pre- compression transform */ #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) @@ -1086,73 +1064,6 @@ fail_wsi: } #endif -#if 0 -static int -rops_perform_user_POLLOUT_h1(struct lws *wsi) -{ - volatile struct lws *vwsi = (volatile struct lws *)wsi; - int n; - - /* priority 1: post compression-transform buffered output */ - - if (lws_has_buffered_out(wsi)) { - lwsl_debug("%s: completing partial\n", __func__); - if (lws_issue_raw(wsi, NULL, 0) < 0) { - lwsl_info("%s signalling to close\n", __func__); - return -1; - } - n = 0; - vwsi->leave_pollout_active = 1; - goto cleanup; - } - - /* priority 2: pre compression-transform buffered output */ - -#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) - if (wsi->http.comp_ctx.buflist_comp || - wsi->http.comp_ctx.may_have_more) { - enum lws_write_protocol wp = LWS_WRITE_HTTP; - - lwsl_info("%s: completing comp partial" - "(buflist_comp %p, may %d)\n", - __func__, wsi->http.comp_ctx.buflist_comp, - wsi->http.comp_ctx.may_have_more); - - if (rops_write_role_protocol_h1(wsi, NULL, 0, &wp) < 0) { - lwsl_info("%s signalling to close\n", __func__); - lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, - "comp write fail"); - } - n = 0; - vwsi->leave_pollout_active = 1; - goto cleanup; - } -#endif - - /* priority 3: if no buffered out and waiting for that... */ - - if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) { - wsi->socket_is_permanently_unusable = 1; - return -1; - } - - /* priority 4: user writeable callback */ - - vwsi = (volatile struct lws *)wsi; - vwsi->leave_pollout_active = 0; - - n = lws_callback_as_writeable(wsi); - -cleanup: - vwsi->handling_pollout = 0; - - if (vwsi->leave_pollout_active) - lws_change_pollfd(wsi, 0, LWS_POLLOUT); - - return n; -} -#endif - static int rops_close_kill_connection_h1(struct lws *wsi, enum lws_close_status reason) { diff --git a/lib/roles/ws/client-parser-ws.c b/lib/roles/ws/client-parser-ws.c index 8fc6ef4f4..4dfb6037a 100644 --- a/lib/roles/ws/client-parser-ws.c +++ b/lib/roles/ws/client-parser-ws.c @@ -57,8 +57,13 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c) } #endif + /* + * Peer may have closed, but that doesn't necessarily mean we should not + * parse any rx we have from them. + * if (wsi->socket_is_permanently_unusable) return -1; + */ switch (wsi->lws_rx_parse_state) { case LWS_RXPS_NEW: