• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2020 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 void
lws_client_conn_wait_timeout(lws_sorted_usec_list_t * sul)28 lws_client_conn_wait_timeout(lws_sorted_usec_list_t *sul)
29 {
30 	struct lws *wsi = lws_container_of(sul, struct lws,
31 					   sul_connect_timeout);
32 
33 	/*
34 	 * This is used to constrain the time we're willing to wait for a
35 	 * connection before giving up on it and retrying.
36 	 */
37 
38 	lwsl_wsi_info(wsi, "connect wait timeout has fired");
39 	lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
40 }
41 
42 void
lws_client_dns_retry_timeout(lws_sorted_usec_list_t * sul)43 lws_client_dns_retry_timeout(lws_sorted_usec_list_t *sul)
44 {
45 	struct lws *wsi = lws_container_of(sul, struct lws,
46 					   sul_connect_timeout);
47 
48 	/*
49 	 * This limits the amount of dns lookups we will try before
50 	 * giving up and failing... it reuses sul_connect_timeout, which
51 	 * isn't officially used until we connected somewhere.
52 	 */
53 
54 	lwsl_wsi_info(wsi, "dns retry");
55 	if (!lws_client_connect_2_dnsreq(wsi))
56 		lwsl_wsi_notice(wsi, "DNS lookup failed");
57 }
58 
59 /*
60  * Figure out if an ongoing connect() has arrived at a final disposition or not
61  *
62  * We can check using getsockopt if our connect actually completed.
63  * Posix connect() allows nonblocking to redo the connect to
64  * find out if it succeeded.
65  */
66 
67 typedef enum {
68 	LCCCR_CONNECTED			= 1,
69 	LCCCR_CONTINUE			= 0,
70 	LCCCR_FAILED			= -1,
71 } lcccr_t;
72 
73 static lcccr_t
lws_client_connect_check(struct lws * wsi)74 lws_client_connect_check(struct lws *wsi)
75 {
76 	int en = 0;
77 #if !defined(WIN32)
78 	int e;
79 	socklen_t sl = sizeof(e);
80 #endif
81 
82 	(void)en;
83 
84 	/*
85 	 * This resets SO_ERROR after reading it.  If there's an error
86 	 * condition, the connect definitively failed.
87 	 */
88 
89 #if !defined(WIN32)
90 	if (!getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR, &e, &sl)) {
91 		en = LWS_ERRNO;
92 		if (!e) {
93 			lwsl_wsi_debug(wsi, "getsockopt: conn OK errno %d", en);
94 
95 			return LCCCR_CONNECTED;
96 		}
97 
98 		lwsl_wsi_notice(wsi, "getsockopt fd %d says e %d",
99 							wsi->desc.sockfd, e);
100 
101 		return LCCCR_FAILED;
102 	}
103 
104 #else
105 
106 	if (!connect(wsi->desc.sockfd, NULL, 0))
107 		return LCCCR_CONNECTED;
108 
109 	en = LWS_ERRNO;
110 
111 	if (en == WSAEISCONN) /* already connected */
112 		return LCCCR_CONNECTED;
113 
114 	if (en == WSAEALREADY) {
115 		/* reset the POLLOUT wait */
116 		if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
117 			lwsl_wsi_notice(wsi, "pollfd failed");
118 	}
119 
120 	if (!en || en == WSAEINVAL ||
121 		   en == WSAEWOULDBLOCK ||
122 		   en == WSAEALREADY) {
123 		lwsl_wsi_debug(wsi, "errno %d", en);
124 		return LCCCR_CONTINUE;
125 	}
126 #endif
127 
128 	lwsl_wsi_notice(wsi, "connect check take as FAILED: errno %d", en);
129 
130 	return LCCCR_FAILED;
131 }
132 
133 /*
134  * We come here to fire off a connect, and to check its disposition later.
135  *
136  * If it did not complete before the individual attempt timeout, we will try to
137  * connect again with the next dns result.
138  */
139 
140 struct lws *
lws_client_connect_3_connect(struct lws * wsi,const char * ads,const struct addrinfo * result,int n,void * opaque)141 lws_client_connect_3_connect(struct lws *wsi, const char *ads,
142 			     const struct addrinfo *result, int n, void *opaque)
143 {
144 #if defined(LWS_WITH_UNIX_SOCK)
145 	struct sockaddr_un sau;
146 #endif
147 	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
148 	const char *cce = "Unable to connect", *iface;
149 	const struct sockaddr *psa = NULL;
150 	uint16_t port = wsi->conn_port;
151 	lws_dns_sort_t *curr;
152 	ssize_t plen = 0;
153 	lws_dll2_t *d;
154 	char dcce[48];
155 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
156 	int cfail;
157 #endif
158 	int m, af = 0;
159 
160 	/*
161 	 * If we come here with result set, we need to convert getaddrinfo
162 	 * results to a lws_dns_sort_t list one time and free the results.
163 	 *
164 	 * We use this pattern because ASYNC_DNS will callback here with the
165 	 * results when it gets them (and may come here more than once, eg, for
166 	 * AAAA then A or vice-versa)
167 	 */
168 
169 	if (result) {
170 		lws_sul_cancel(&wsi->sul_connect_timeout);
171 
172 #if defined(LWS_WITH_CONMON)
173 		/* append a copy from before the sorting */
174 		lws_conmon_append_copy_new_dns_results(wsi, result);
175 #endif
176 
177 		lws_sort_dns(wsi, result);
178 #if defined(LWS_WITH_SYS_ASYNC_DNS)
179 		lws_async_dns_freeaddrinfo(&result);
180 #else
181 		freeaddrinfo((struct addrinfo *)result);
182 #endif
183 		result = NULL;
184 	}
185 
186 #if defined(LWS_WITH_UNIX_SOCK)
187 	memset(&sau, 0, sizeof(sau));
188 #endif
189 
190 	/*
191 	 * async dns calls back here for everybody who cares when it gets a
192 	 * result... but if we are piggybacking, we do not want to connect
193 	 * ourselves
194 	 */
195 
196 	if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue))
197 		return wsi;
198 
199 	if (n &&  /* calling back with a problem */
200 	    !wsi->dns_sorted_list.count && /* there's no results */
201 	    !lws_socket_is_valid(wsi->desc.sockfd) && /* no attempt ongoing */
202 	    !wsi->speculative_connect_owner.count /* no spec attempt */ ) {
203 		lwsl_wsi_notice(wsi, "dns lookup failed %d", n);
204 
205 		/*
206 		 * DNS lookup itself failed... let's try again until we
207 		 * timeout
208 		 */
209 
210 		lwsi_set_state(wsi, LRS_UNCONNECTED);
211 		lws_sul_schedule(wsi->a.context, 0, &wsi->sul_connect_timeout,
212 				 lws_client_dns_retry_timeout,
213 						 LWS_USEC_PER_SEC);
214 		return wsi;
215 
216 //		cce = "dns lookup failed";
217 //		goto oom4;
218 	}
219 
220 	/*
221 	 * We come back here again when we think the connect() may have
222 	 * completed one way or the other, we can't proceed until we know we
223 	 * actually connected.
224 	 */
225 
226 	if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
227 	    lws_socket_is_valid(wsi->desc.sockfd)) {
228 
229 		if (!wsi->dns_sorted_list.count &&
230 		    !wsi->sul_connect_timeout.list.owner)
231 			/* no dns results and no ongoing timeout for one */
232 			goto connect_to;
233 
234 		switch (lws_client_connect_check(wsi)) {
235 		case LCCCR_CONNECTED:
236 			/*
237 			 * Oh, it has happened...
238 			 */
239 			goto conn_good;
240 		case LCCCR_CONTINUE:
241 			return NULL;
242 		default:
243 			lws_snprintf(dcce, sizeof(dcce), "conn fail: errno %d",
244 								LWS_ERRNO);
245 			cce = dcce;
246 			lwsl_wsi_debug(wsi, "%s", dcce);
247 			lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
248 			goto try_next_dns_result_fds;
249 		}
250 	}
251 
252 #if defined(LWS_WITH_UNIX_SOCK)
253 
254 	if (ads && *ads == '+') {
255 		ads++;
256 		memset(&wsi->sa46_peer, 0, sizeof(wsi->sa46_peer));
257 		af = sau.sun_family = AF_UNIX;
258 		strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
259 		sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';
260 
261 		lwsl_wsi_info(wsi, "Unix skt: %s", ads);
262 
263 		if (sau.sun_path[0] == '@')
264 			sau.sun_path[0] = '\0';
265 
266 		goto ads_known;
267 	}
268 #endif
269 
270 #if defined(LWS_WITH_SYS_ASYNC_DNS)
271 	if (n == LADNS_RET_FAILED) {
272 		lwsl_wsi_notice(wsi, "adns failed %s", ads);
273 		/*
274 		 * Caller that is giving us LADNS_RET_FAILED will deal
275 		 * with cleanup
276 		 */
277 		return NULL;
278 	}
279 #endif
280 
281 	/*
282 	 * Let's try directly connecting to each of the results in turn until
283 	 * one works, or we run out of results...
284 	 *
285 	 * We have a sorted dll2 list with the head one most preferable
286 	 */
287 
288 next_dns_result:
289 
290 	cce = "Unable to connect";
291 
292 	if (!wsi->dns_sorted_list.count)
293 		goto failed1;
294 
295 	/*
296 	 * Copy the wsi head sorted dns result into the wsi->sa46_peer, and
297 	 * remove and free the original from the sorted list
298 	 */
299 
300 	d = lws_dll2_get_head(&wsi->dns_sorted_list);
301 	curr = lws_container_of(d, lws_dns_sort_t, list);
302 
303 	lws_dll2_remove(&curr->list);
304 	wsi->sa46_peer = curr->dest;
305 #if defined(LWS_WITH_NETLINK)
306 	wsi->peer_route_uidx = curr->uidx;
307 	lwsl_wsi_info(wsi, "peer_route_uidx %d", wsi->peer_route_uidx);
308 #endif
309 
310 	lws_free(curr);
311 
312 	sa46_sockport(&wsi->sa46_peer, htons(port));
313 
314 	psa = sa46_sockaddr(&wsi->sa46_peer);
315 	n = (int)sa46_socklen(&wsi->sa46_peer);
316 
317 #if defined(LWS_WITH_UNIX_SOCK)
318 ads_known:
319 #endif
320 
321 	/*
322 	 * Now we prepared psa, if not already connecting, create the related
323 	 * socket and add to the fds
324 	 */
325 
326 	if (!lws_socket_is_valid(wsi->desc.sockfd)) {
327 
328 		if (wsi->a.context->event_loop_ops->check_client_connect_ok &&
329 		    wsi->a.context->event_loop_ops->check_client_connect_ok(wsi)
330 		) {
331 			cce = "waiting for event loop watcher to close";
332 			goto oom4;
333 		}
334 
335 #if defined(LWS_WITH_UNIX_SOCK)
336 		af = 0;
337 		if (wsi->unix_skt) {
338 			af = AF_UNIX;
339 			wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
340 		}
341 		else
342 #endif
343 		{
344 			af = wsi->sa46_peer.sa4.sin_family;
345 			wsi->desc.sockfd = socket(wsi->sa46_peer.sa4.sin_family,
346 						  SOCK_STREAM, 0);
347 		}
348 
349 		if (!lws_socket_is_valid(wsi->desc.sockfd)) {
350 			lws_snprintf(dcce, sizeof(dcce),
351 				     "conn fail: skt creation: errno %d",
352 								LWS_ERRNO);
353 			cce = dcce;
354 			lwsl_wsi_warn(wsi, "%s", dcce);
355 			goto try_next_dns_result;
356 		}
357 
358 		if (lws_plat_set_socket_options(wsi->a.vhost, wsi->desc.sockfd,
359 #if defined(LWS_WITH_UNIX_SOCK)
360 						wsi->unix_skt)) {
361 #else
362 						0)) {
363 #endif
364 			lws_snprintf(dcce, sizeof(dcce),
365 				     "conn fail: skt options: errno %d",
366 								LWS_ERRNO);
367 			cce = dcce;
368 			lwsl_wsi_warn(wsi, "%s", dcce);
369 			goto try_next_dns_result_closesock;
370 		}
371 
372 		/* apply requested socket options */
373 		if (lws_plat_set_socket_options_ip(wsi->desc.sockfd,
374 						   wsi->c_pri, wsi->flags))
375 			lwsl_wsi_warn(wsi, "unable to set ip options");
376 
377 		lwsl_wsi_debug(wsi, "WAITING_CONNECT");
378 		lwsi_set_state(wsi, LRS_WAITING_CONNECT);
379 
380 		if (wsi->a.context->event_loop_ops->sock_accept)
381 			if (wsi->a.context->event_loop_ops->sock_accept(wsi)) {
382 				lws_snprintf(dcce, sizeof(dcce),
383 					     "conn fail: sock accept");
384 				cce = dcce;
385 				lwsl_wsi_warn(wsi, "%s", dcce);
386 				goto try_next_dns_result_closesock;
387 			}
388 
389 		lws_pt_lock(pt, __func__);
390 		if (__insert_wsi_socket_into_fds(wsi->a.context, wsi)) {
391 			lws_snprintf(dcce, sizeof(dcce),
392 				     "conn fail: insert fd");
393 			cce = dcce;
394 			lws_pt_unlock(pt);
395 			goto try_next_dns_result_closesock;
396 		}
397 		lws_pt_unlock(pt);
398 
399 		/*
400 		 * The fd + wsi combination is entered into the wsi tables
401 		 * at this point, with a pollfd
402 		 *
403 		 * Past here, we can't simply free the structs as error
404 		 * handling as oom4 does.
405 		 *
406 		 * We can run the whole close flow, or unpick the fds inclusion
407 		 * and anything else we have done.
408 		 */
409 
410 		if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
411 			lws_snprintf(dcce, sizeof(dcce),
412 				     "conn fail: change pollfd");
413 			cce = dcce;
414 			goto try_next_dns_result_fds;
415 		}
416 
417 		if (!wsi->a.protocol)
418 			wsi->a.protocol = &wsi->a.vhost->protocols[0];
419 
420 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
421 				wsi->a.vhost->connect_timeout_secs);
422 
423 		iface = lws_wsi_client_stash_item(wsi, CIS_IFACE,
424 						  _WSI_TOKEN_CLIENT_IFACE);
425 
426 		if (iface && *iface) {
427 			m = lws_socket_bind(wsi->a.vhost, wsi, wsi->desc.sockfd,
428 					    0, iface, af);
429 			if (m < 0) {
430 				lws_snprintf(dcce, sizeof(dcce),
431 					     "conn fail: socket bind");
432 				cce = dcce;
433 				goto try_next_dns_result_fds;
434 			}
435 		}
436 	}
437 
438 #if defined(LWS_WITH_UNIX_SOCK)
439 	if (wsi->unix_skt) {
440 		psa = (const struct sockaddr *)&sau;
441 		if (sau.sun_path[0])
442 			n = (int)(sizeof(uint16_t) + strlen(sau.sun_path));
443 		else
444 			n = (int)(sizeof(uint16_t) +
445 					strlen(&sau.sun_path[1]) + 1);
446 	} else
447 #endif
448 
449 	if (!psa) /* coverity */
450 		goto try_next_dns_result_fds;
451 
452 	/*
453 	 * The actual connection attempt
454 	 */
455 
456 #if defined(LWS_ESP_PLATFORM)
457 	errno = 0;
458 #endif
459 
460 	/* grab a copy for peer tracking */
461 #if defined(LWS_WITH_UNIX_SOCK)
462 	if (!wsi->unix_skt)
463 #endif
464 		memmove(&wsi->sa46_peer, psa, (unsigned int)n);
465 
466 	/*
467 	 * Finally, make the actual connection attempt
468 	 */
469 
470 #if defined(LWS_WITH_SYS_METRICS)
471 	if (wsi->cal_conn.mt) {
472 		lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
473 	}
474 	lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mt_conn_tcp);
475 #endif
476 
477 	wsi->socket_is_permanently_unusable = 0;
478 
479 	if (lws_fi(&wsi->fic, "conn_cb_rej") ||
480 	    user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
481 			LWS_CALLBACK_CONNECTING, wsi->user_space,
482 			(void *)(intptr_t)wsi->desc.sockfd, 0)) {
483 		lwsl_wsi_info(wsi, "CONNECTION CB closed");
484 		goto failed1;
485 	}
486 
487 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
488 	cfail = lws_fi(&wsi->fic, "connfail");
489 	if (cfail)
490 		m = -1;
491 	else
492 #endif
493 		m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa,
494 			    (socklen_t)n);
495 
496 #if defined(LWS_WITH_CONMON)
497 	wsi->conmon_datum = lws_now_usecs();
498 	wsi->conmon.ciu_sockconn = 0;
499 #endif
500 
501 	if (m == -1) {
502 		/*
503 		 * Since we're nonblocking, connect not having completed is not
504 		 * necessarily indicating any problem... we have to look at
505 		 * either errno or the socket to understand if we actually
506 		 * failed already...
507 		 */
508 
509 		int errno_copy = LWS_ERRNO;
510 
511 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
512 		if (cfail)
513 			/* fake an abnormal, fatal situation */
514 			errno_copy = 999;
515 #endif
516 
517 		lwsl_wsi_debug(wsi, "connect: fd %d errno: %d",
518 				wsi->desc.sockfd, errno_copy);
519 
520 		if (errno_copy &&
521 		    errno_copy != LWS_EALREADY &&
522 		    errno_copy != LWS_EINPROGRESS &&
523 		    errno_copy != LWS_EWOULDBLOCK
524 #ifdef _WIN32
525 		 && errno_copy != WSAEINVAL
526                  && errno_copy != WSAEISCONN
527 #endif
528 		) {
529 			/*
530 			 * The connect() failed immediately...
531 			 */
532 
533 #if defined(LWS_WITH_CONMON)
534 			wsi->conmon.ciu_sockconn = (lws_conmon_interval_us_t)
535 					(lws_now_usecs() - wsi->conmon_datum);
536 #endif
537 
538 			lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
539 
540 #if defined(_DEBUG)
541 #if defined(LWS_WITH_UNIX_SOCK)
542 			if (!wsi->unix_skt) {
543 #endif
544 
545 			char nads[48];
546 
547 			lws_sa46_write_numeric_address(&wsi->sa46_peer, nads,
548 						       sizeof(nads));
549 
550 			lws_snprintf(dcce, sizeof(dcce),
551 				     "conn fail: errno %d: %s:%d",
552 						errno_copy, nads, port);
553 			cce = dcce;
554 
555 			wsi->sa46_peer.sa4.sin_family = 0;
556 			lwsl_wsi_info(wsi, "%s", cce);
557 #if defined(LWS_WITH_UNIX_SOCK)
558 			} else {
559 				lws_snprintf(dcce, sizeof(dcce),
560 					     "conn fail: errno %d: UDS %s",
561 							       errno_copy, ads);
562 				cce = dcce;
563 			}
564 #endif
565 #endif
566 
567 			goto try_next_dns_result_fds;
568 		}
569 
570 #if defined(WIN32)
571 		if (lws_plat_check_connection_error(wsi))
572 			goto try_next_dns_result_fds;
573 
574 		if (errno_copy == WSAEISCONN)
575 			goto conn_good;
576 #endif
577 
578 		/*
579 		 * The connection attempt is ongoing asynchronously... let's set
580 		 * a specialized timeout for this connect attempt completion, it
581 		 * uses wsi->sul_connect_timeout just for this purpose
582 		 */
583 
584 		lws_sul_schedule(wsi->a.context, 0, &wsi->sul_connect_timeout,
585 				 lws_client_conn_wait_timeout,
586 				 wsi->a.context->timeout_secs *
587 						 LWS_USEC_PER_SEC);
588 
589 		/*
590 		 * must do specifically a POLLOUT poll to hear
591 		 * about the connect completion
592 		 */
593 		if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
594 			goto try_next_dns_result_fds;
595 
596 		return wsi;
597 	}
598 
599 conn_good:
600 
601 	/*
602 	 * The connection has happened
603 	 */
604 
605 #if defined(LWS_WITH_CONMON)
606 	wsi->conmon.ciu_sockconn = (lws_conmon_interval_us_t)
607 					(lws_now_usecs() - wsi->conmon_datum);
608 #endif
609 
610 #if !defined(LWS_PLAT_OPTEE)
611 	{
612 		socklen_t salen = sizeof(wsi->sa46_local);
613 #if defined(_DEBUG)
614 		char buf[64];
615 #endif
616 		if (getsockname((int)wsi->desc.sockfd,
617 				(struct sockaddr *)&wsi->sa46_local,
618 				&salen) == -1)
619 			lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
620 #if defined(_DEBUG)
621 #if defined(LWS_WITH_UNIX_SOCK)
622 		if (wsi->unix_skt)
623 			buf[0] = '\0';
624 		else
625 #endif
626 			lws_sa46_write_numeric_address(&wsi->sa46_local, buf, sizeof(buf));
627 
628 		lwsl_wsi_info(wsi, "source ads %s", buf);
629 #endif
630 	}
631 #endif
632 
633 	lws_sul_cancel(&wsi->sul_connect_timeout);
634 	lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
635 
636 	lws_addrinfo_clean(wsi);
637 
638 	if (wsi->a.protocol)
639 		wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
640 					  wsi->user_space, NULL, 0);
641 
642 	lwsl_wsi_debug(wsi, "going into connect_4");
643 
644 	return lws_client_connect_4_established(wsi, NULL, plen);
645 
646 oom4:
647 	/*
648 	 * We get here if we're trying to clean up a connection attempt that
649 	 * didn't make it as far as getting inserted into the wsi / fd tables
650 	 */
651 
652 	if (lwsi_role_client(wsi) && wsi->a.protocol
653 				/* && lwsi_state_est(wsi) */)
654 		lws_inform_client_conn_fail(wsi,(void *)cce, strlen(cce));
655 
656 	/* take care that we might be inserted in fds already */
657 	if (wsi->position_in_fds_table != LWS_NO_FDS_POS)
658 		/* do the full wsi close flow */
659 		goto failed1;
660 
661 	lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
662 
663 	/*
664 	 * We can't be an active client connection any more, if we thought
665 	 * that was what we were going to be doing.  It should be if we are
666 	 * failing by oom4 path, we are still called by
667 	 * lws_client_connect_via_info() and will be returning NULL to that,
668 	 * so nobody else should have had a chance to queue on us.
669 	 */
670 	{
671 		struct lws_vhost *vhost = wsi->a.vhost;
672 		lws_sockfd_type sfd = wsi->desc.sockfd;
673 
674 		//lws_vhost_lock(vhost);
675 		__lws_free_wsi(wsi); /* acquires vhost lock in wsi reset */
676 		//lws_vhost_unlock(vhost);
677 
678 		sanity_assert_no_wsi_traces(vhost->context, wsi);
679 		sanity_assert_no_sockfd_traces(vhost->context, sfd);
680 	}
681 
682 	return NULL;
683 
684 connect_to:
685 	/*
686 	 * It looks like the sul_connect_timeout fired
687 	 */
688 	lwsl_wsi_info(wsi, "abandoning connect due to timeout");
689 
690 try_next_dns_result_fds:
691 	lws_pt_lock(pt, __func__);
692 	__remove_wsi_socket_from_fds(wsi);
693 	lws_pt_unlock(pt);
694 
695 try_next_dns_result_closesock:
696 	/*
697 	 * We are killing the socket but leaving
698 	 */
699 	compatible_close(wsi->desc.sockfd);
700 	wsi->desc.sockfd = LWS_SOCK_INVALID;
701 
702 try_next_dns_result:
703 	lws_sul_cancel(&wsi->sul_connect_timeout);
704 	if (lws_dll2_get_head(&wsi->dns_sorted_list))
705 		goto next_dns_result;
706 
707 	lws_addrinfo_clean(wsi);
708 	lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
709 
710 failed1:
711 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect3");
712 
713 	return NULL;
714 }
715