close: make close notification go through writable
Until now we took the approach if just writing the close notification broke something, we didn't care because we were closing the connection anyway. But with lws_meta, breaking stuff in the parent connection would be a sticky problem outliving the closing child connection. So this adds a new wsi state LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION and makes the send go via the writable callback mechanism.
This commit is contained in:
parent
faa1526b39
commit
3b0066cb3f
6 changed files with 44 additions and 25 deletions
|
@ -558,6 +558,7 @@ utf8_fail: lwsl_info("utf8 error\n");
|
|||
lws_remove_wsi_from_draining_ext_list(wsi);
|
||||
|
||||
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
|
||||
wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||
|
||||
wsi->state == LWSS_AWAITING_CLOSE_ACK)
|
||||
goto already_done;
|
||||
|
||||
|
|
|
@ -229,6 +229,7 @@ postbody_completion:
|
|||
|
||||
case LWSS_ESTABLISHED:
|
||||
case LWSS_AWAITING_CLOSE_ACK:
|
||||
case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION:
|
||||
case LWSS_SHUTDOWN:
|
||||
if (lws_handshake_client(wsi, &buf, (size_t)len))
|
||||
goto bail;
|
||||
|
|
|
@ -337,6 +337,7 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
|
|||
return;
|
||||
|
||||
/* we tried the polite way... */
|
||||
case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION:
|
||||
case LWSS_AWAITING_CLOSE_ACK:
|
||||
goto just_kill_connection;
|
||||
|
||||
|
@ -453,29 +454,14 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
|
|||
#if defined (LWS_WITH_ESP8266)
|
||||
wsi->close_is_pending_send_completion = 1;
|
||||
#endif
|
||||
n = lws_write(wsi, &wsi->u.ws.ping_payload_buf[LWS_PRE],
|
||||
wsi->u.ws.close_in_ping_buffer_len,
|
||||
LWS_WRITE_CLOSE);
|
||||
if (n >= 0) {
|
||||
/*
|
||||
* we have sent a nice protocol level indication we
|
||||
* now wish to close, we should not send anything more
|
||||
*/
|
||||
wsi->state = LWSS_AWAITING_CLOSE_ACK;
|
||||
|
||||
/*
|
||||
* ...and we should wait for a reply for a bit
|
||||
* out of politeness
|
||||
*/
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 1);
|
||||
lwsl_debug("sent close indication, awaiting ack\n");
|
||||
lwsl_debug("waiting for chance to send close\n");
|
||||
wsi->waiting_to_send_close_frame = 1;
|
||||
wsi->state = LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION;
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 2);
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lwsl_info("close: sending close packet failed, hanging up\n");
|
||||
|
||||
/* else, the send failed and we should just hang up */
|
||||
return;
|
||||
}
|
||||
|
||||
just_kill_connection:
|
||||
|
@ -639,6 +625,7 @@ just_kill_connection:
|
|||
((wsi->state_pre_close == LWSS_ESTABLISHED) ||
|
||||
(wsi->state_pre_close == LWSS_RETURNED_CLOSE_ALREADY) ||
|
||||
(wsi->state_pre_close == LWSS_AWAITING_CLOSE_ACK) ||
|
||||
(wsi->state_pre_close == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION) ||
|
||||
(wsi->state_pre_close == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) ||
|
||||
(wsi->mode == LWSCM_WS_CLIENT && wsi->state_pre_close == LWSS_HTTP) ||
|
||||
(wsi->mode == LWSCM_WS_SERVING && wsi->state_pre_close == LWSS_HTTP))) {
|
||||
|
|
|
@ -3619,6 +3619,8 @@ enum pending_timeout {
|
|||
PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY = 20,
|
||||
PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY = 21,
|
||||
PENDING_TIMEOUT_KILLED_BY_SSL_INFO = 22,
|
||||
PENDING_TIMEOUT_KILLED_BY_PARENT = 23,
|
||||
PENDING_TIMEOUT_CLOSE_SEND = 24,
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
};
|
||||
|
|
|
@ -488,6 +488,7 @@ enum lws_connection_states {
|
|||
LWSS_ESTABLISHED,
|
||||
LWSS_CLIENT_HTTP_ESTABLISHED,
|
||||
LWSS_CLIENT_UNCONNECTED,
|
||||
LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION,
|
||||
LWSS_RETURNED_CLOSE_ALREADY,
|
||||
LWSS_AWAITING_CLOSE_ACK,
|
||||
LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE,
|
||||
|
@ -1648,6 +1649,7 @@ struct lws {
|
|||
unsigned int sending_chunked:1;
|
||||
unsigned int already_did_cce:1;
|
||||
unsigned int told_user_closed:1;
|
||||
unsigned int waiting_to_send_close_frame:1;
|
||||
unsigned int ipv6:1;
|
||||
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
|
|
|
@ -58,13 +58,13 @@ lws_calllback_as_writeable(struct lws *wsi)
|
|||
n = LWS_CALLBACK_HTTP_WRITEABLE;
|
||||
break;
|
||||
}
|
||||
lwsl_debug("%s: %p (user=%p)\n", __func__, wsi, wsi->user_space);
|
||||
|
||||
return user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, (enum lws_callback_reasons) n,
|
||||
wsi->user_space, NULL, 0);
|
||||
}
|
||||
|
||||
int
|
||||
LWS_VISIBLE int
|
||||
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
||||
{
|
||||
int write_type = LWS_WRITE_PONG;
|
||||
|
@ -74,7 +74,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
#endif
|
||||
int ret, m, n;
|
||||
|
||||
//lwsl_err("%s: %p\n", __func__, wsi);
|
||||
// lwsl_err("%s: %p\n", __func__, wsi);
|
||||
|
||||
wsi->leave_pollout_active = 0;
|
||||
wsi->handling_pollout = 1;
|
||||
|
@ -144,7 +144,29 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
#endif
|
||||
|
||||
/* Priority 3: pending control packets (pong or close)
|
||||
*
|
||||
* 3a: close notification packet requested from close api
|
||||
*/
|
||||
|
||||
if (wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION) {
|
||||
lwsl_debug("sending close packet\n");
|
||||
wsi->waiting_to_send_close_frame = 0;
|
||||
n = lws_write(wsi, &wsi->u.ws.ping_payload_buf[LWS_PRE],
|
||||
wsi->u.ws.close_in_ping_buffer_len,
|
||||
LWS_WRITE_CLOSE);
|
||||
if (n >= 0) {
|
||||
wsi->state = LWSS_AWAITING_CLOSE_ACK;
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 1);
|
||||
lwsl_debug("sent close indication, awaiting ack\n");
|
||||
|
||||
goto bail_ok;
|
||||
}
|
||||
|
||||
goto bail_die;
|
||||
}
|
||||
|
||||
/* else, the send failed and we should just hang up */
|
||||
|
||||
if ((wsi->state == LWSS_ESTABLISHED &&
|
||||
wsi->u.ws.ping_pending_flag) ||
|
||||
(wsi->state == LWSS_RETURNED_CLOSE_ALREADY &&
|
||||
|
@ -319,7 +341,6 @@ user_service:
|
|||
wsi->handling_pollout = 0;
|
||||
|
||||
/* cannot get leave_pollout_active set after the above */
|
||||
|
||||
if (!eff && wsi->leave_pollout_active)
|
||||
/* got set inbetween sampling eff and clearing
|
||||
* handling_pollout, force POLLOUT on */
|
||||
|
@ -1039,11 +1060,15 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
|
||||
/* 1: something requested a callback when it was OK to write */
|
||||
|
||||
if (wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION)
|
||||
lwsl_notice("xxx\n");
|
||||
|
||||
if ((pollfd->revents & LWS_POLLOUT) &&
|
||||
((wsi->state == LWSS_ESTABLISHED ||
|
||||
wsi->state == LWSS_HTTP2_ESTABLISHED ||
|
||||
wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS ||
|
||||
wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
|
||||
wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||
|
||||
wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE)) &&
|
||||
lws_handle_POLLOUT_event(wsi, pollfd)) {
|
||||
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY)
|
||||
|
@ -1053,6 +1078,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
}
|
||||
|
||||
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
|
||||
wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||
|
||||
wsi->state == LWSS_AWAITING_CLOSE_ACK) {
|
||||
/*
|
||||
* we stopped caring about anything except control
|
||||
|
|
Loading…
Add table
Reference in a new issue