void
lws_free_wsi(struct lws *wsi)
{
+ struct lws_context_per_thread *pt;
+ int n;
+
if (!wsi)
return;
+ pt = &wsi->context->pt[(int)wsi->tsi];
+
/* Protocol user data may be allocated either internally by lws
* or by specified the user.
* We should only free what we allocated. */
/* we may not have an ah, but may be on the waiting list... */
lwsl_info("ah det due to close\n");
+ /* we're closing, losing some rx is OK */
+ lws_header_table_force_to_detachable_state(wsi);
lws_header_table_detach(wsi, 0);
+ lws_pt_lock(pt);
+ for (n = 0; n < wsi->context->max_http_header_pool; n++) {
+ if (pt->ah_pool[n].in_use &&
+ pt->ah_pool[n].wsi == wsi) {
+ lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
+ pt->ah_pool[n].in_use = 0;
+ pt->ah_pool[n].wsi = NULL;
+ pt->ah_count_in_use--;
+ }
+ }
+ lws_pt_unlock(pt);
+
+ /* since we will destroy the wsi, make absolutely sure now */
+
+ lws_ssl_remove_wsi_from_buffered_list(wsi);
+ lws_remove_from_timeout_list(wsi);
+
wsi->context->count_wsi_allocated--;
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
wsi->context->count_wsi_allocated);
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 !defined(LWS_NO_CLIENT)
+ if (wsi->mode == LWSCM_HTTP_CLIENT ||
+ wsi->mode == LWSCM_WSCL_WAITING_CONNECT ||
+ wsi->mode == LWSCM_WSCL_WAITING_PROXY_REPLY ||
+ wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE ||
+ wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE2 ||
+ wsi->mode == LWSCM_WSCL_WAITING_SSL ||
+ wsi->mode == LWSCM_WSCL_WAITING_SERVER_REPLY ||
+ wsi->mode == LWSCM_WSCL_WAITING_EXTENSION_CONNECT ||
+ wsi->mode == LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY ||
+ wsi->mode == LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY ||
+ wsi->mode == LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY)
+ if (wsi->u.hdr.stash)
+ lws_free_set_NULL(wsi->u.hdr.stash);
+#endif
+
if (wsi->mode == LWSCM_RAW) {
wsi->protocol->callback(wsi,
LWS_CALLBACK_RAW_CLOSE, wsi->user_space, NULL, 0);
/* 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->socket_is_permanently_unusable = 1;
#ifdef LWS_USE_LIBUV
- 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);
+ 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);
struct addrinfo ai, *res;
struct sockaddr_in addr4;
- if (rip)
- rip[0] = '\0';
+ rip[0] = '\0';
name[0] = '\0';
addr4.sin_family = AF_UNSPEC;
name, name_len, NULL, 0, 0))
return -1;
#endif
- if (!rip)
- return 0;
if (getaddrinfo(name, NULL, &ai, &result))
return -1;
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)
{