• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 #if defined(LWS_WITH_CLIENT)
28 static int
lws_close_trans_q_leader(struct lws_dll2 * d,void * user)29 lws_close_trans_q_leader(struct lws_dll2 *d, void *user)
30 {
31 	struct lws *w = lws_container_of(d, struct lws, dll2_cli_txn_queue);
32 
33 	__lws_close_free_wsi(w, -1, "trans q leader closing");
34 
35 	return 0;
36 }
37 #endif
38 
39 void
__lws_reset_wsi(struct lws * wsi)40 __lws_reset_wsi(struct lws *wsi)
41 {
42 	if (!wsi)
43 		return;
44 
45 #if defined(LWS_WITH_CLIENT)
46 
47 	lws_free_set_NULL(wsi->cli_hostname_copy);
48 
49 	/*
50 	 * if we have wsi in our transaction queue, if we are closing we
51 	 * must go through and close all those first
52 	 */
53 	if (wsi->vhost) {
54 
55 		/* we are no longer an active client connection that can piggyback */
56 		lws_dll2_remove(&wsi->dll_cli_active_conns);
57 
58 		lws_dll2_foreach_safe(&wsi->dll2_cli_txn_queue_owner, NULL,
59 				      lws_close_trans_q_leader);
60 
61 		/*
62 		 * !!! If we are closing, but we have pending pipelined
63 		 * transaction results we already sent headers for, that's going
64 		 * to destroy sync for HTTP/1 and leave H2 stream with no live
65 		 * swsi.`
66 		 *
67 		 * However this is normal if we are being closed because the
68 		 * transaction queue leader is closing.
69 		 */
70 		lws_dll2_remove(&wsi->dll2_cli_txn_queue);
71 	}
72 #endif
73 
74 	if (wsi->vhost)
75 		lws_dll2_remove(&wsi->vh_awaiting_socket);
76 
77 	/*
78 	 * Protocol user data may be allocated either internally by lws
79 	 * or by specified the user. We should only free what we allocated.
80 	 */
81 	if (wsi->protocol && wsi->protocol->per_session_data_size &&
82 	    wsi->user_space && !wsi->user_space_externally_allocated)
83 		lws_free_set_NULL(wsi->user_space);
84 
85 	lws_buflist_destroy_all_segments(&wsi->buflist);
86 	lws_buflist_destroy_all_segments(&wsi->buflist_out);
87 #if defined(LWS_WITH_UDP)
88 	lws_free_set_NULL(wsi->udp);
89 #endif
90 	wsi->retry = 0;
91 
92 #if defined(LWS_WITH_CLIENT)
93 	lws_dll2_remove(&wsi->dll2_cli_txn_queue);
94 	lws_dll2_remove(&wsi->dll_cli_active_conns);
95 #endif
96 
97 #if defined(LWS_WITH_SYS_ASYNC_DNS)
98 	lws_async_dns_cancel(wsi);
99 #endif
100 
101 #if defined(LWS_WITH_HTTP_PROXY)
102 	if (wsi->http.buflist_post_body)
103 		lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body);
104 #endif
105 
106 	if (wsi->vhost && wsi->vhost->lserv_wsi == wsi)
107 		wsi->vhost->lserv_wsi = NULL;
108 #if defined(LWS_WITH_CLIENT)
109 	if (wsi->vhost)
110 		lws_dll2_remove(&wsi->dll_cli_active_conns);
111 #endif
112 	wsi->context->count_wsi_allocated--;
113 
114 	__lws_same_vh_protocol_remove(wsi);
115 #if defined(LWS_WITH_CLIENT)
116 	lws_free_set_NULL(wsi->stash);
117 	lws_free_set_NULL(wsi->cli_hostname_copy);
118 #endif
119 
120 #if defined(LWS_WITH_PEER_LIMITS)
121 	lws_peer_track_wsi_close(wsi->context, wsi->peer);
122 	wsi->peer = NULL;
123 #endif
124 
125 	/* since we will destroy the wsi, make absolutely sure now */
126 
127 #if defined(LWS_WITH_OPENSSL)
128 	__lws_ssl_remove_wsi_from_buffered_list(wsi);
129 #endif
130 	__lws_wsi_remove_from_sul(wsi);
131 
132 	if (wsi->role_ops->destroy_role)
133 		wsi->role_ops->destroy_role(wsi);
134 
135 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
136 	__lws_header_table_detach(wsi, 0);
137 #endif
138 }
139 
140 void
__lws_free_wsi(struct lws * wsi)141 __lws_free_wsi(struct lws *wsi)
142 {
143 	if (!wsi)
144 		return;
145 
146 	__lws_reset_wsi(wsi);
147 
148 	if (wsi->context->event_loop_ops->destroy_wsi)
149 		wsi->context->event_loop_ops->destroy_wsi(wsi);
150 
151 	lws_vhost_unbind_wsi(wsi);
152 
153 	lwsl_debug("%s: %p, remaining wsi %d, tsi fds count %d\n", __func__, wsi,
154 			wsi->context->count_wsi_allocated,
155 			wsi->context->pt[(int)wsi->tsi].fds_count);
156 
157 	lws_free(wsi);
158 }
159 
160 
161 void
lws_remove_child_from_any_parent(struct lws * wsi)162 lws_remove_child_from_any_parent(struct lws *wsi)
163 {
164 	struct lws **pwsi;
165 	int seen = 0;
166 
167 	if (!wsi->parent)
168 		return;
169 
170 	/* detach ourselves from parent's child list */
171 	pwsi = &wsi->parent->child_list;
172 	while (*pwsi) {
173 		if (*pwsi == wsi) {
174 			lwsl_info("%s: detach %p from parent %p\n", __func__,
175 				  wsi, wsi->parent);
176 
177 			if (wsi->parent->protocol)
178 				wsi->parent->protocol->callback(wsi,
179 						LWS_CALLBACK_CHILD_CLOSING,
180 					       wsi->parent->user_space, wsi, 0);
181 
182 			*pwsi = wsi->sibling_list;
183 			seen = 1;
184 			break;
185 		}
186 		pwsi = &(*pwsi)->sibling_list;
187 	}
188 	if (!seen)
189 		lwsl_err("%s: failed to detach from parent\n", __func__);
190 
191 	wsi->parent = NULL;
192 }
193 
194 #if defined(LWS_WITH_CLIENT)
195 void
lws_inform_client_conn_fail(struct lws * wsi,void * arg,size_t len)196 lws_inform_client_conn_fail(struct lws *wsi, void *arg, size_t len)
197 {
198 	lws_addrinfo_clean(wsi);
199 
200 	if (wsi->already_did_cce)
201 		return;
202 
203 	wsi->already_did_cce = 1;
204 	lws_stats_bump(&wsi->context->pt[(int)wsi->tsi],
205 		       LWSSTATS_C_CONNS_CLIENT_FAILED, 1);
206 
207 	if (!wsi->protocol)
208 		return;
209 
210 	if (!wsi->client_suppress_CONNECTION_ERROR)
211 		wsi->protocol->callback(wsi,
212 					LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
213 					wsi->user_space, arg, len);
214 }
215 #endif
216 
217 void
lws_addrinfo_clean(struct lws * wsi)218 lws_addrinfo_clean(struct lws *wsi)
219 {
220 #if defined(LWS_WITH_CLIENT)
221 	if (!wsi->dns_results)
222 		return;
223 
224 #if defined(LWS_WITH_SYS_ASYNC_DNS)
225 	lws_async_dns_freeaddrinfo(&wsi->dns_results);
226 #else
227 	freeaddrinfo((struct addrinfo *)wsi->dns_results);
228 #endif
229 	wsi->dns_results = NULL;
230 #endif
231 }
232 
233 void
__lws_close_free_wsi(struct lws * wsi,enum lws_close_status reason,const char * caller)234 __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
235 		     const char *caller)
236 {
237 	struct lws_context_per_thread *pt;
238 	const struct lws_protocols *pro;
239 	struct lws_context *context;
240 	struct lws *wsi1, *wsi2;
241 	int n, ccb;
242 
243 	lwsl_info("%s: %p: caller: %s\n", __func__, wsi, caller);
244 
245 	if (!wsi)
246 		return;
247 
248 	lws_access_log(wsi);
249 
250 	if (!lws_dll2_is_detached(&wsi->dll_buflist)) {
251 		lwsl_info("%s: wsi %p: going down with stuff in buflist\n",
252 				__func__, wsi); }
253 
254 	context = wsi->context;
255 	pt = &context->pt[(int)wsi->tsi];
256 	lws_stats_bump(pt, LWSSTATS_C_API_CLOSE, 1);
257 
258 #if defined(LWS_WITH_CLIENT)
259 
260 	lws_free_set_NULL(wsi->cli_hostname_copy);
261 
262 	lws_addrinfo_clean(wsi);
263 #endif
264 
265 #if defined(LWS_WITH_HTTP2)
266 	if (wsi->mux_stream_immortal)
267 		lws_http_close_immortal(wsi);
268 #endif
269 
270 	/* if we have children, close them first */
271 	if (wsi->child_list) {
272 		wsi2 = wsi->child_list;
273 		while (wsi2) {
274 			wsi1 = wsi2->sibling_list;
275 			wsi2->parent = NULL;
276 			/* stop it doing shutdown processing */
277 			wsi2->socket_is_permanently_unusable = 1;
278 			__lws_close_free_wsi(wsi2, reason,
279 					     "general child recurse");
280 			wsi2 = wsi1;
281 		}
282 		wsi->child_list = NULL;
283 	}
284 
285 #if defined(LWS_ROLE_RAW_FILE)
286 	if (wsi->role_ops == &role_ops_raw_file) {
287 		lws_remove_child_from_any_parent(wsi);
288 		__remove_wsi_socket_from_fds(wsi);
289 		if (wsi->protocol)
290 			wsi->protocol->callback(wsi, wsi->role_ops->close_cb[0],
291 					wsi->user_space, NULL, 0);
292 		goto async_close;
293 	}
294 #endif
295 
296 	wsi->wsistate_pre_close = wsi->wsistate;
297 
298 #ifdef LWS_WITH_CGI
299 	if (wsi->role_ops == &role_ops_cgi) {
300 
301 		// lwsl_debug("%s: closing stdwsi index %d\n", __func__, (int)wsi->lsp_channel);
302 
303 		/* we are not a network connection, but a handler for CGI io */
304 		if (wsi->parent && wsi->parent->http.cgi) {
305 
306 			if (wsi->parent->child_list == wsi && !wsi->sibling_list)
307 				lws_cgi_remove_and_kill(wsi->parent);
308 
309 			/* end the binding between us and master */
310 			if (wsi->parent->http.cgi)
311 				wsi->parent->http.cgi->lsp->stdwsi[(int)wsi->lsp_channel] =
312 									NULL;
313 		}
314 		wsi->socket_is_permanently_unusable = 1;
315 
316 		goto just_kill_connection;
317 	}
318 
319 	if (wsi->http.cgi)
320 		lws_cgi_remove_and_kill(wsi);
321 #endif
322 
323 #if defined(LWS_WITH_CLIENT)
324 	lws_free_set_NULL(wsi->stash);
325 #endif
326 
327 	if (wsi->role_ops == &role_ops_raw_skt) {
328 		wsi->socket_is_permanently_unusable = 1;
329 		goto just_kill_connection;
330 	}
331 #if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
332 	if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
333 	    wsi->http.fop_fd != NULL)
334 		lws_vfs_file_close(&wsi->http.fop_fd);
335 #endif
336 
337 	if (lwsi_state(wsi) == LRS_DEAD_SOCKET)
338 		return;
339 
340 	if (wsi->socket_is_permanently_unusable ||
341 	    reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY ||
342 	    lwsi_state(wsi) == LRS_SHUTDOWN)
343 		goto just_kill_connection;
344 
345 	switch (lwsi_state_PRE_CLOSE(wsi)) {
346 	case LRS_DEAD_SOCKET:
347 		return;
348 
349 	/* we tried the polite way... */
350 	case LRS_WAITING_TO_SEND_CLOSE:
351 	case LRS_AWAITING_CLOSE_ACK:
352 	case LRS_RETURNED_CLOSE:
353 		goto just_kill_connection;
354 
355 	case LRS_FLUSHING_BEFORE_CLOSE:
356 		if (lws_has_buffered_out(wsi)
357 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
358 		    || wsi->http.comp_ctx.buflist_comp ||
359 		    wsi->http.comp_ctx.may_have_more
360 #endif
361 		 ) {
362 			lws_callback_on_writable(wsi);
363 			return;
364 		}
365 		lwsl_info("%p: end LRS_FLUSHING_BEFORE_CLOSE\n", wsi);
366 		goto just_kill_connection;
367 	default:
368 		if (lws_has_buffered_out(wsi)
369 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
370 				|| wsi->http.comp_ctx.buflist_comp ||
371 		    wsi->http.comp_ctx.may_have_more
372 #endif
373 		) {
374 			lwsl_info("%p: LRS_FLUSHING_BEFORE_CLOSE\n", wsi);
375 			lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
376 			__lws_set_timeout(wsi,
377 				PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5);
378 			return;
379 		}
380 		break;
381 	}
382 
383 	if (lwsi_state(wsi) == LRS_WAITING_CONNECT ||
384 	    lwsi_state(wsi) == LRS_WAITING_DNS ||
385 	    lwsi_state(wsi) == LRS_H1C_ISSUE_HANDSHAKE)
386 		goto just_kill_connection;
387 
388 	if (!wsi->told_user_closed && wsi->user_space && wsi->protocol &&
389 	    wsi->protocol_bind_balance) {
390 		wsi->protocol->callback(wsi,
391 				wsi->role_ops->protocol_unbind_cb[
392 				       !!lwsi_role_server(wsi)],
393 				       wsi->user_space, (void *)__func__, 0);
394 		wsi->protocol_bind_balance = 0;
395 	}
396 
397 	/*
398 	 * signal we are closing, lws_write will
399 	 * add any necessary version-specific stuff.  If the write fails,
400 	 * no worries we are closing anyway.  If we didn't initiate this
401 	 * close, then our state has been changed to
402 	 * LRS_RETURNED_CLOSE and we will skip this.
403 	 *
404 	 * Likewise if it's a second call to close this connection after we
405 	 * sent the close indication to the peer already, we are in state
406 	 * LRS_AWAITING_CLOSE_ACK and will skip doing this a second time.
407 	 */
408 
409 	if (wsi->role_ops->close_via_role_protocol &&
410 	    wsi->role_ops->close_via_role_protocol(wsi, reason))
411 		return;
412 
413 just_kill_connection:
414 
415 #if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
416 	if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
417 	    wsi->http.fop_fd != NULL)
418 		lws_vfs_file_close(&wsi->http.fop_fd);
419 #endif
420 
421 #if defined(LWS_WITH_SYS_ASYNC_DNS)
422 	lws_async_dns_cancel(wsi);
423 #endif
424 
425 #if defined(LWS_WITH_HTTP_PROXY)
426 	if (wsi->http.buflist_post_body)
427 		lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body);
428 #endif
429 #if defined(LWS_WITH_UDP)
430 	if (wsi->udp)
431 		lws_free_set_NULL(wsi->udp);
432 #endif
433 
434 	if (wsi->role_ops->close_kill_connection)
435 		wsi->role_ops->close_kill_connection(wsi, reason);
436 
437 	n = 0;
438 
439 	if (!wsi->told_user_closed && wsi->user_space &&
440 	    wsi->protocol_bind_balance && wsi->protocol) {
441 		lwsl_debug("%s: %p: DROP_PROTOCOL %s\n", __func__, wsi,
442 			   wsi->protocol ? wsi->protocol->name: "NULL");
443 		if (wsi->protocol)
444 			wsi->protocol->callback(wsi,
445 				wsi->role_ops->protocol_unbind_cb[
446 				       !!lwsi_role_server(wsi)],
447 				       wsi->user_space, (void *)__func__, 0);
448 		wsi->protocol_bind_balance = 0;
449 	}
450 
451 #if defined(LWS_WITH_CLIENT)
452 	if ((lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY ||
453 	     lwsi_state(wsi) == LRS_WAITING_DNS ||
454 	     lwsi_state(wsi) == LRS_WAITING_CONNECT) &&
455 	     !wsi->already_did_cce && wsi->protocol) {
456 		static const char _reason[] = "closed before established";
457 
458 		lws_inform_client_conn_fail(wsi,
459 			(void *)_reason, sizeof(_reason));
460 	}
461 #endif
462 
463 	/*
464 	 * Testing with ab shows that we have to stage the socket close when
465 	 * the system is under stress... shutdown any further TX, change the
466 	 * state to one that won't emit anything more, and wait with a timeout
467 	 * for the POLLIN to show a zero-size rx before coming back and doing
468 	 * the actual close.
469 	 */
470 	if (wsi->role_ops != &role_ops_raw_skt && !lwsi_role_client(wsi) &&
471 	    lwsi_state(wsi) != LRS_SHUTDOWN &&
472 	    lwsi_state(wsi) != LRS_UNCONNECTED &&
473 	    reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY &&
474 	    !wsi->socket_is_permanently_unusable) {
475 
476 #if defined(LWS_WITH_TLS)
477 		if (lws_is_ssl(wsi) && wsi->tls.ssl) {
478 			n = 0;
479 			switch (__lws_tls_shutdown(wsi)) {
480 			case LWS_SSL_CAPABLE_DONE:
481 			case LWS_SSL_CAPABLE_ERROR:
482 			case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
483 			case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
484 			case LWS_SSL_CAPABLE_MORE_SERVICE:
485 				break;
486 			}
487 		} else
488 #endif
489 		{
490 			lwsl_info("%s: shutdown conn: %p (sk %d, state 0x%x)\n",
491 				  __func__, wsi, (int)(lws_intptr_t)wsi->desc.sockfd,
492 				  lwsi_state(wsi));
493 			if (!wsi->socket_is_permanently_unusable &&
494 			    lws_socket_is_valid(wsi->desc.sockfd)) {
495 				wsi->socket_is_permanently_unusable = 1;
496 				n = shutdown(wsi->desc.sockfd, SHUT_WR);
497 			}
498 		}
499 		if (n)
500 			lwsl_debug("closing: shutdown (state 0x%x) ret %d\n",
501 				   lwsi_state(wsi), LWS_ERRNO);
502 
503 		/*
504 		 * This causes problems on WINCE / ESP32 with disconnection
505 		 * when the events are half closing connection
506 		 */
507 #if !defined(_WIN32_WCE) && !defined(LWS_PLAT_FREERTOS)
508 		/* libuv: no event available to guarantee completion */
509 		if (!wsi->socket_is_permanently_unusable &&
510 		    lws_socket_is_valid(wsi->desc.sockfd) &&
511 		    lwsi_state(wsi) != LRS_SHUTDOWN &&
512 		    (context->event_loop_ops->flags & LELOF_ISPOLL)) {
513 			__lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
514 			lwsi_set_state(wsi, LRS_SHUTDOWN);
515 			__lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
516 					  context->timeout_secs);
517 
518 			return;
519 		}
520 #endif
521 	}
522 
523 	lwsl_debug("%s: real just_kill_connection: %p (sockfd %d)\n", __func__,
524 		   wsi, wsi->desc.sockfd);
525 
526 #ifdef LWS_WITH_HUBBUB
527 	if (wsi->http.rw) {
528 		lws_rewrite_destroy(wsi->http.rw);
529 		wsi->http.rw = NULL;
530 	}
531 #endif
532 
533 	if (wsi->http.pending_return_headers)
534 		lws_free_set_NULL(wsi->http.pending_return_headers);
535 
536 	/*
537 	 * we won't be servicing or receiving anything further from this guy
538 	 * delete socket from the internal poll list if still present
539 	 */
540 	__lws_ssl_remove_wsi_from_buffered_list(wsi);
541 	__lws_wsi_remove_from_sul(wsi);
542 
543 	//if (wsi->told_event_loop_closed) // cgi std close case (dummy-callback)
544 	//	return;
545 
546 	// lwsl_notice("%s: wsi %p, fd %d\n", __func__, wsi, wsi->desc.sockfd);
547 
548 	/* checking return redundant since we anyway close */
549 	if (wsi->desc.sockfd != LWS_SOCK_INVALID)
550 		__remove_wsi_socket_from_fds(wsi);
551 	else
552 		__lws_same_vh_protocol_remove(wsi);
553 
554 	lwsi_set_state(wsi, LRS_DEAD_SOCKET);
555 	lws_buflist_destroy_all_segments(&wsi->buflist);
556 	lws_dll2_remove(&wsi->dll_buflist);
557 
558 	if (wsi->role_ops->close_role)
559 	    wsi->role_ops->close_role(pt, wsi);
560 
561 	/* tell the user it's all over for this guy */
562 
563 	ccb = 0;
564 	if ((lwsi_state_est_PRE_CLOSE(wsi) ||
565 	    /* raw skt adopted but didn't complete tls hs should CLOSE */
566 	    (wsi->role_ops == &role_ops_raw_skt && !lwsi_role_client(wsi)) ||
567 	     lwsi_state_PRE_CLOSE(wsi) == LRS_WAITING_SERVER_REPLY) &&
568 	    !wsi->told_user_closed &&
569 	    wsi->role_ops->close_cb[lwsi_role_server(wsi)]) {
570 		if (!wsi->upgraded_to_http2 || !lwsi_role_client(wsi))
571 			ccb = 1;
572 			/*
573 			 * The network wsi for a client h2 connection shouldn't
574 			 * call back for its role: the child stream connections
575 			 * own the role.  Otherwise h2 will call back closed
576 			 * one too many times as the children do it and then
577 			 * the closing network stream.
578 			 */
579 	}
580 
581 	if (!wsi->told_user_closed &&
582 	    !lws_dll2_is_detached(&wsi->vh_awaiting_socket))
583 		/*
584 		 * He's a guy who go started with dns, but failed or is
585 		 * caught with a shutdown before he got the result.  We have
586 		 * to issue him a close cb
587 		 */
588 		ccb = 1;
589 
590 	pro = wsi->protocol;
591 
592 #if defined(LWS_WITH_CLIENT)
593 	if (!ccb && (lwsi_state_PRE_CLOSE(wsi) & LWSIFS_NOT_EST) &&
594 			lwsi_role_client(wsi)) {
595 		lws_inform_client_conn_fail(wsi, "Closed before conn", 18);
596 	}
597 #endif
598 	if (ccb) {
599 
600 		if (!wsi->protocol && wsi->vhost && wsi->vhost->protocols)
601 			pro = &wsi->vhost->protocols[0];
602 
603 		if (pro)
604 			pro->callback(wsi,
605 				wsi->role_ops->close_cb[lwsi_role_server(wsi)],
606 				wsi->user_space, NULL, 0);
607 		wsi->told_user_closed = 1;
608 	}
609 
610 #if defined(LWS_ROLE_RAW_FILE)
611 async_close:
612 #endif
613 	lws_remove_child_from_any_parent(wsi);
614 	wsi->socket_is_permanently_unusable = 1;
615 
616 	if (wsi->context->event_loop_ops->wsi_logical_close)
617 		if (wsi->context->event_loop_ops->wsi_logical_close(wsi))
618 			return;
619 
620 	__lws_close_free_wsi_final(wsi);
621 }
622 
623 void
__lws_close_free_wsi_final(struct lws * wsi)624 __lws_close_free_wsi_final(struct lws *wsi)
625 {
626 	int n;
627 
628 	if (!wsi->shadow &&
629 	    lws_socket_is_valid(wsi->desc.sockfd) && !lws_ssl_close(wsi)) {
630 		lwsl_debug("%s: wsi %p: fd %d\n", __func__, wsi, wsi->desc.sockfd);
631 		n = compatible_close(wsi->desc.sockfd);
632 		if (n)
633 			lwsl_debug("closing: close ret %d\n", LWS_ERRNO);
634 
635 		wsi->desc.sockfd = LWS_SOCK_INVALID;
636 	}
637 
638 	/* outermost destroy notification for wsi (user_space still intact) */
639 	if (wsi->vhost)
640 		wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
641 						  wsi->user_space, NULL, 0);
642 
643 #ifdef LWS_WITH_CGI
644 	if (wsi->http.cgi) {
645 		lws_spawn_piped_destroy(&wsi->http.cgi->lsp);
646 		lws_free_set_NULL(wsi->http.cgi);
647 	}
648 #endif
649 
650 	__lws_free_wsi(wsi);
651 }
652 
653 
654 void
lws_close_free_wsi(struct lws * wsi,enum lws_close_status reason,const char * caller)655 lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *caller)
656 {
657 	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
658 
659 	lws_pt_lock(pt, __func__);
660 	__lws_close_free_wsi(wsi, reason, caller);
661 	lws_pt_unlock(pt);
662 }
663 
664 
665