struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
time_t now;
+ if (secs == LWS_TO_KILL_SYNC) {
+ lws_remove_from_timeout_list(wsi);
+ lwsl_debug("synchronously killing %p\n", wsi);
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ return;
+ }
+
lws_pt_lock(pt);
time(&now);
if (*pwsi == wsi) {
lwsl_info("%s: detach %p from parent %p\n",
__func__, wsi, wsi->parent);
+
+ if (wsi->parent->protocol)
+ wsi->parent->protocol->callback(wsi,
+ LWS_CALLBACK_CHILD_CLOSING,
+ wsi->parent->user_space, wsi, 0);
+
*pwsi = wsi->sibling_list;
seen = 1;
break;
struct lws_tokens eff_buf;
int n, m, ret;
+ lwsl_debug("%s: %p\n", __func__, wsi);
+
if (!wsi)
return;
}
#endif
- if (wsi->u.hdr.ah)
- /* we're closing, losing some rx is OK */
- wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
+ /* we're closing, losing some rx is OK */
+ lws_header_table_force_to_detachable_state(wsi);
context = wsi->context;
pt = &context->pt[(int)wsi->tsi];
return;
/* we tried the polite way... */
+ case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION:
case LWSS_AWAITING_CLOSE_ACK:
goto just_kill_connection;
#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");
-
- return;
- }
- lwsl_info("close: sending close packet failed, hanging up\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);
- /* else, the send failed and we should just hang up */
+ return;
}
just_kill_connection:
/* checking return redundant since we anyway close */
if (wsi->desc.sockfd != LWS_SOCK_INVALID)
remove_wsi_socket_from_fds(wsi);
+ else
+ lws_same_vh_protocol_remove(wsi);
#if defined(LWS_WITH_ESP8266)
espconn_disconnect(wsi->desc.sockfd);
((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))) {
wsi->socket_is_permanently_unusable = 1;
#ifdef LWS_USE_LIBUV
- if (LWS_LIBUV_ENABLED(context)) {
- lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
- /* libuv has to do his own close handle processing asynchronously */
- lws_libuv_closehandle(wsi);
+ if (!wsi->parent_carries_io)
+ if (LWS_LIBUV_ENABLED(context)) {
+ if (wsi->listener) {
+ lwsl_debug("%s: stopping listner libuv poll\n", __func__);
+ uv_poll_stop(&wsi->w_read.uv_watcher);
+ }
+ lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
+ /* libuv has to do his own close handle processing asynchronously */
+ lws_libuv_closehandle(wsi);
- return;
- }
+ return;
+ }
#endif
lws_close_free_wsi_final(wsi);
int af = AF_INET;
void *p, *q;
+ if (wsi->parent_carries_io)
+ wsi = wsi->parent;
+
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(wsi->vhost)) {
len = sizeof(sin6);
return wsi->u.ws.final && !wsi->u.ws.rx_packet_length && !wsi->u.ws.rx_draining_ext;
}
+LWS_VISIBLE int
+lws_is_first_fragment(struct lws *wsi)
+{
+ return wsi->u.ws.first_fragment;
+}
+
LWS_VISIBLE unsigned char
lws_get_reserved_bits(struct lws *wsi)
{
}
LWS_VISIBLE LWS_EXTERN void
+lws_set_parent_carries_io(struct lws *wsi)
+{
+ wsi->parent_carries_io = 1;
+}
+
+LWS_VISIBLE LWS_EXTERN void *
+lws_get_opaque_parent_data(const struct lws *wsi)
+{
+ return wsi->opaque_parent_data;
+}
+
+LWS_VISIBLE LWS_EXTERN void
+lws_set_opaque_parent_data(struct lws *wsi, void *data)
+{
+ wsi->opaque_parent_data = data;
+}
+
+LWS_VISIBLE LWS_EXTERN int
+lws_get_child_pending_on_writable(const struct lws *wsi)
+{
+ return wsi->parent_pending_cb_on_writable;
+}
+
+LWS_VISIBLE LWS_EXTERN void
+lws_clear_child_pending_on_writable(struct lws *wsi)
+{
+ wsi->parent_pending_cb_on_writable = 0;
+}
+
+LWS_VISIBLE LWS_EXTERN int
+lws_get_close_length(struct lws *wsi)
+{
+ return wsi->u.ws.close_in_ping_buffer_len;
+}
+
+LWS_VISIBLE LWS_EXTERN unsigned char *
+lws_get_close_payload(struct lws *wsi)
+{
+ return &wsi->u.ws.ping_payload_buf[LWS_PRE];
+}
+
+LWS_VISIBLE LWS_EXTERN void
lws_close_reason(struct lws *wsi, enum lws_close_status status,
unsigned char *buf, size_t len)
{
* Actually having made the env, as a cgi we don't need the ah
* any more
*/
- if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen)
+ if (lws_header_table_is_in_detachable_state(wsi))
lws_header_table_detach(wsi, 0);
/* we are ready with the redirection pipes... run the thing */