xref: /aosp_15_r20/external/libwebsockets/lib/core-net/client/connect3.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2020 Andy Green <[email protected]>
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 	/*
187 	 * async dns calls back here for everybody who cares when it gets a
188 	 * result... but if we are piggybacking, we do not want to connect
189 	 * ourselves
190 	 */
191 
192 	if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue))
193 		return wsi;
194 
195 	if (n &&  /* calling back with a problem */
196 	    !wsi->dns_sorted_list.count && /* there's no results */
197 	    !lws_socket_is_valid(wsi->desc.sockfd) && /* no attempt ongoing */
198 	    !wsi->speculative_connect_owner.count /* no spec attempt */ ) {
199 		lwsl_wsi_notice(wsi, "dns lookup failed %d", n);
200 
201 		/*
202 		 * DNS lookup itself failed... let's try again until we
203 		 * timeout
204 		 */
205 
206 		lwsi_set_state(wsi, LRS_UNCONNECTED);
207 		lws_sul_schedule(wsi->a.context, 0, &wsi->sul_connect_timeout,
208 				 lws_client_dns_retry_timeout,
209 						 LWS_USEC_PER_SEC);
210 		return wsi;
211 
212 //		cce = "dns lookup failed";
213 //		goto oom4;
214 	}
215 
216 	/*
217 	 * We come back here again when we think the connect() may have
218 	 * completed one way or the other, we can't proceed until we know we
219 	 * actually connected.
220 	 */
221 
222 	if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
223 	    lws_socket_is_valid(wsi->desc.sockfd)) {
224 
225 		if (!wsi->dns_sorted_list.count &&
226 		    !wsi->sul_connect_timeout.list.owner)
227 			/* no dns results and no ongoing timeout for one */
228 			goto connect_to;
229 
230 		switch (lws_client_connect_check(wsi)) {
231 		case LCCCR_CONNECTED:
232 			/*
233 			 * Oh, it has happened...
234 			 */
235 			goto conn_good;
236 		case LCCCR_CONTINUE:
237 			return NULL;
238 		default:
239 			lws_snprintf(dcce, sizeof(dcce), "conn fail: errno %d",
240 								LWS_ERRNO);
241 			cce = dcce;
242 			lwsl_wsi_debug(wsi, "%s", dcce);
243 			lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
244 			goto try_next_dns_result_fds;
245 		}
246 	}
247 
248 #if defined(LWS_WITH_UNIX_SOCK)
249 	if (ads && *ads == '+') {
250 		ads++;
251 		memset(&wsi->sa46_peer, 0, sizeof(wsi->sa46_peer));
252 		memset(&sau, 0, sizeof(sau));
253 		af = sau.sun_family = AF_UNIX;
254 		strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
255 		sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';
256 
257 		lwsl_wsi_info(wsi, "Unix skt: %s", ads);
258 
259 		if (sau.sun_path[0] == '@')
260 			sau.sun_path[0] = '\0';
261 
262 		goto ads_known;
263 	}
264 #endif
265 
266 #if defined(LWS_WITH_SYS_ASYNC_DNS)
267 	if (n == LADNS_RET_FAILED) {
268 		lwsl_wsi_notice(wsi, "adns failed %s", ads);
269 		/*
270 		 * Caller that is giving us LADNS_RET_FAILED will deal
271 		 * with cleanup
272 		 */
273 		return NULL;
274 	}
275 #endif
276 
277 	/*
278 	 * Let's try directly connecting to each of the results in turn until
279 	 * one works, or we run out of results...
280 	 *
281 	 * We have a sorted dll2 list with the head one most preferable
282 	 */
283 
284 next_dns_result:
285 
286 	cce = "Unable to connect";
287 
288 	if (!wsi->dns_sorted_list.count)
289 		goto failed1;
290 
291 	/*
292 	 * Copy the wsi head sorted dns result into the wsi->sa46_peer, and
293 	 * remove and free the original from the sorted list
294 	 */
295 
296 	d = lws_dll2_get_head(&wsi->dns_sorted_list);
297 	curr = lws_container_of(d, lws_dns_sort_t, list);
298 
299 	lws_dll2_remove(&curr->list);
300 	wsi->sa46_peer = curr->dest;
301 #if defined(LWS_WITH_NETLINK)
302 	wsi->peer_route_uidx = curr->uidx;
303 	lwsl_wsi_info(wsi, "peer_route_uidx %d", wsi->peer_route_uidx);
304 #endif
305 
306 	lws_free(curr);
307 
308 	sa46_sockport(&wsi->sa46_peer, htons(port));
309 
310 	psa = sa46_sockaddr(&wsi->sa46_peer);
311 	n = (int)sa46_socklen(&wsi->sa46_peer);
312 
313 #if defined(LWS_WITH_UNIX_SOCK)
314 ads_known:
315 #endif
316 
317 	/*
318 	 * Now we prepared psa, if not already connecting, create the related
319 	 * socket and add to the fds
320 	 */
321 
322 	if (!lws_socket_is_valid(wsi->desc.sockfd)) {
323 
324 		if (wsi->a.context->event_loop_ops->check_client_connect_ok &&
325 		    wsi->a.context->event_loop_ops->check_client_connect_ok(wsi)
326 		) {
327 			cce = "waiting for event loop watcher to close";
328 			goto oom4;
329 		}
330 
331 #if defined(LWS_WITH_UNIX_SOCK)
332 		af = 0;
333 		if (wsi->unix_skt) {
334 			af = AF_UNIX;
335 			wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
336 		}
337 		else
338 #endif
339 		{
340 			af = wsi->sa46_peer.sa4.sin_family;
341 			wsi->desc.sockfd = socket(wsi->sa46_peer.sa4.sin_family,
342 						  SOCK_STREAM, 0);
343 		}
344 
345 		if (!lws_socket_is_valid(wsi->desc.sockfd)) {
346 			lws_snprintf(dcce, sizeof(dcce),
347 				     "conn fail: skt creation: errno %d",
348 								LWS_ERRNO);
349 			cce = dcce;
350 			lwsl_wsi_warn(wsi, "%s", dcce);
351 			goto try_next_dns_result;
352 		}
353 
354 		if (lws_plat_set_socket_options(wsi->a.vhost, wsi->desc.sockfd,
355 #if defined(LWS_WITH_UNIX_SOCK)
356 						wsi->unix_skt)) {
357 #else
358 						0)) {
359 #endif
360 			lws_snprintf(dcce, sizeof(dcce),
361 				     "conn fail: skt options: errno %d",
362 								LWS_ERRNO);
363 			cce = dcce;
364 			lwsl_wsi_warn(wsi, "%s", dcce);
365 			goto try_next_dns_result_closesock;
366 		}
367 
368 		/* apply requested socket options */
369 		if (lws_plat_set_socket_options_ip(wsi->desc.sockfd,
370 						   wsi->c_pri, wsi->flags))
371 			lwsl_wsi_warn(wsi, "unable to set ip options");
372 
373 		lwsl_wsi_debug(wsi, "WAITING_CONNECT");
374 		lwsi_set_state(wsi, LRS_WAITING_CONNECT);
375 
376 		if (wsi->a.context->event_loop_ops->sock_accept)
377 			if (wsi->a.context->event_loop_ops->sock_accept(wsi)) {
378 				lws_snprintf(dcce, sizeof(dcce),
379 					     "conn fail: sock accept");
380 				cce = dcce;
381 				lwsl_wsi_warn(wsi, "%s", dcce);
382 				goto try_next_dns_result_closesock;
383 			}
384 
385 		lws_pt_lock(pt, __func__);
386 		if (__insert_wsi_socket_into_fds(wsi->a.context, wsi)) {
387 			lws_snprintf(dcce, sizeof(dcce),
388 				     "conn fail: insert fd");
389 			cce = dcce;
390 			lws_pt_unlock(pt);
391 			goto try_next_dns_result_closesock;
392 		}
393 		lws_pt_unlock(pt);
394 
395 		/*
396 		 * The fd + wsi combination is entered into the wsi tables
397 		 * at this point, with a pollfd
398 		 *
399 		 * Past here, we can't simply free the structs as error
400 		 * handling as oom4 does.
401 		 *
402 		 * We can run the whole close flow, or unpick the fds inclusion
403 		 * and anything else we have done.
404 		 */
405 
406 		if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
407 			lws_snprintf(dcce, sizeof(dcce),
408 				     "conn fail: change pollfd");
409 			cce = dcce;
410 			goto try_next_dns_result_fds;
411 		}
412 
413 		if (!wsi->a.protocol)
414 			wsi->a.protocol = &wsi->a.vhost->protocols[0];
415 
416 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
417 				wsi->a.vhost->connect_timeout_secs);
418 
419 		iface = lws_wsi_client_stash_item(wsi, CIS_IFACE,
420 						  _WSI_TOKEN_CLIENT_IFACE);
421 
422 		if (iface && *iface) {
423 			m = lws_socket_bind(wsi->a.vhost, wsi, wsi->desc.sockfd,
424 					    0, iface, af);
425 			if (m < 0) {
426 				lws_snprintf(dcce, sizeof(dcce),
427 					     "conn fail: socket bind");
428 				cce = dcce;
429 				goto try_next_dns_result_fds;
430 			}
431 		}
432 	}
433 
434 #if defined(LWS_WITH_UNIX_SOCK)
435 	if (wsi->unix_skt) {
436 		psa = (const struct sockaddr *)&sau;
437 		if (sau.sun_path[0])
438 			n = (int)(sizeof(uint16_t) + strlen(sau.sun_path));
439 		else
440 			n = (int)(sizeof(uint16_t) +
441 					strlen(&sau.sun_path[1]) + 1);
442 	} else
443 #endif
444 
445 	if (!psa) /* coverity */
446 		goto try_next_dns_result_fds;
447 
448 	/*
449 	 * The actual connection attempt
450 	 */
451 
452 #if defined(LWS_ESP_PLATFORM)
453 	errno = 0;
454 #endif
455 
456 	/* grab a copy for peer tracking */
457 #if defined(LWS_WITH_UNIX_SOCK)
458 	if (!wsi->unix_skt)
459 #endif
460 		memmove(&wsi->sa46_peer, psa, (unsigned int)n);
461 
462 	/*
463 	 * Finally, make the actual connection attempt
464 	 */
465 
466 #if defined(LWS_WITH_SYS_METRICS)
467 	if (wsi->cal_conn.mt) {
468 		lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
469 	}
470 	lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mt_conn_tcp);
471 #endif
472 
473 	wsi->socket_is_permanently_unusable = 0;
474 
475 	if (lws_fi(&wsi->fic, "conn_cb_rej") ||
476 	    user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
477 			LWS_CALLBACK_CONNECTING, wsi->user_space,
478 			(void *)(intptr_t)wsi->desc.sockfd, 0)) {
479 		lwsl_wsi_info(wsi, "CONNECTION CB closed");
480 		goto failed1;
481 	}
482 
483 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
484 	cfail = lws_fi(&wsi->fic, "connfail");
485 	if (cfail)
486 		m = -1;
487 	else
488 #endif
489 		m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa,
490 			    (socklen_t)n);
491 
492 #if defined(LWS_WITH_CONMON)
493 	wsi->conmon_datum = lws_now_usecs();
494 	wsi->conmon.ciu_sockconn = 0;
495 #endif
496 
497 	if (m == -1) {
498 		/*
499 		 * Since we're nonblocking, connect not having completed is not
500 		 * necessarily indicating any problem... we have to look at
501 		 * either errno or the socket to understand if we actually
502 		 * failed already...
503 		 */
504 
505 		int errno_copy = LWS_ERRNO;
506 
507 #if defined(LWS_WITH_SYS_FAULT_INJECTION)
508 		if (cfail)
509 			/* fake an abnormal, fatal situation */
510 			errno_copy = 999;
511 #endif
512 
513 		lwsl_wsi_debug(wsi, "connect: fd %d errno: %d",
514 				wsi->desc.sockfd, errno_copy);
515 
516 		if (errno_copy &&
517 		    errno_copy != LWS_EALREADY &&
518 		    errno_copy != LWS_EINPROGRESS &&
519 		    errno_copy != LWS_EWOULDBLOCK
520 #ifdef _WIN32
521 		 && errno_copy != WSAEINVAL
522                  && errno_copy != WSAEISCONN
523 #endif
524 		) {
525 			/*
526 			 * The connect() failed immediately...
527 			 */
528 
529 #if defined(LWS_WITH_CONMON)
530 			wsi->conmon.ciu_sockconn = (lws_conmon_interval_us_t)
531 					(lws_now_usecs() - wsi->conmon_datum);
532 #endif
533 
534 			lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
535 
536 #if defined(_DEBUG)
537 #if defined(LWS_WITH_UNIX_SOCK)
538 			if (!wsi->unix_skt) {
539 #endif
540 
541 			char nads[48];
542 
543 			lws_sa46_write_numeric_address(&wsi->sa46_peer, nads,
544 						       sizeof(nads));
545 
546 			lws_snprintf(dcce, sizeof(dcce),
547 				     "conn fail: errno %d: %s:%d",
548 						errno_copy, nads, port);
549 			cce = dcce;
550 
551 			wsi->sa46_peer.sa4.sin_family = 0;
552 			lwsl_wsi_info(wsi, "%s", cce);
553 #if defined(LWS_WITH_UNIX_SOCK)
554 			} else {
555 				lws_snprintf(dcce, sizeof(dcce),
556 					     "conn fail: errno %d: UDS %s",
557 							       errno_copy, ads);
558 				cce = dcce;
559 			}
560 #endif
561 #endif
562 
563 			goto try_next_dns_result_fds;
564 		}
565 
566 #if defined(WIN32)
567 		if (lws_plat_check_connection_error(wsi))
568 			goto try_next_dns_result_fds;
569 
570 		if (errno_copy == WSAEISCONN)
571 			goto conn_good;
572 #endif
573 
574 		/*
575 		 * The connection attempt is ongoing asynchronously... let's set
576 		 * a specialized timeout for this connect attempt completion, it
577 		 * uses wsi->sul_connect_timeout just for this purpose
578 		 */
579 
580 		lws_sul_schedule(wsi->a.context, 0, &wsi->sul_connect_timeout,
581 				 lws_client_conn_wait_timeout,
582 				 wsi->a.context->timeout_secs *
583 						 LWS_USEC_PER_SEC);
584 
585 		/*
586 		 * must do specifically a POLLOUT poll to hear
587 		 * about the connect completion
588 		 */
589 		if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
590 			goto try_next_dns_result_fds;
591 
592 		return wsi;
593 	}
594 
595 conn_good:
596 
597 	/*
598 	 * The connection has happened
599 	 */
600 
601 #if defined(LWS_WITH_CONMON)
602 	wsi->conmon.ciu_sockconn = (lws_conmon_interval_us_t)
603 					(lws_now_usecs() - wsi->conmon_datum);
604 #endif
605 
606 #if !defined(LWS_PLAT_OPTEE)
607 	{
608 		socklen_t salen = sizeof(wsi->sa46_local);
609 #if defined(_DEBUG)
610 		char buf[64];
611 #endif
612 		if (getsockname((int)wsi->desc.sockfd,
613 				(struct sockaddr *)&wsi->sa46_local,
614 				&salen) == -1)
615 			lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
616 #if defined(_DEBUG)
617 #if defined(LWS_WITH_UNIX_SOCK)
618 		if (wsi->unix_skt)
619 			buf[0] = '\0';
620 		else
621 #endif
622 			lws_sa46_write_numeric_address(&wsi->sa46_local, buf, sizeof(buf));
623 
624 		lwsl_wsi_info(wsi, "source ads %s", buf);
625 #endif
626 	}
627 #endif
628 
629 	lws_sul_cancel(&wsi->sul_connect_timeout);
630 	lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
631 
632 	lws_addrinfo_clean(wsi);
633 
634 	if (wsi->a.protocol)
635 		wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
636 					  wsi->user_space, NULL, 0);
637 
638 	lwsl_wsi_debug(wsi, "going into connect_4");
639 
640 	return lws_client_connect_4_established(wsi, NULL, plen);
641 
642 oom4:
643 	/*
644 	 * We get here if we're trying to clean up a connection attempt that
645 	 * didn't make it as far as getting inserted into the wsi / fd tables
646 	 */
647 
648 	if (lwsi_role_client(wsi) && wsi->a.protocol
649 				/* && lwsi_state_est(wsi) */)
650 		lws_inform_client_conn_fail(wsi,(void *)cce, strlen(cce));
651 
652 	/* take care that we might be inserted in fds already */
653 	if (wsi->position_in_fds_table != LWS_NO_FDS_POS)
654 		/* do the full wsi close flow */
655 		goto failed1;
656 
657 	lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
658 
659 	/*
660 	 * We can't be an active client connection any more, if we thought
661 	 * that was what we were going to be doing.  It should be if we are
662 	 * failing by oom4 path, we are still called by
663 	 * lws_client_connect_via_info() and will be returning NULL to that,
664 	 * so nobody else should have had a chance to queue on us.
665 	 */
666 	{
667 		struct lws_vhost *vhost = wsi->a.vhost;
668 		lws_sockfd_type sfd = wsi->desc.sockfd;
669 
670 		//lws_vhost_lock(vhost);
671 		__lws_free_wsi(wsi); /* acquires vhost lock in wsi reset */
672 		//lws_vhost_unlock(vhost);
673 
674 		sanity_assert_no_wsi_traces(vhost->context, wsi);
675 		sanity_assert_no_sockfd_traces(vhost->context, sfd);
676 	}
677 
678 	return NULL;
679 
680 connect_to:
681 	/*
682 	 * It looks like the sul_connect_timeout fired
683 	 */
684 	lwsl_wsi_info(wsi, "abandoning connect due to timeout");
685 
686 try_next_dns_result_fds:
687 	lws_pt_lock(pt, __func__);
688 	__remove_wsi_socket_from_fds(wsi);
689 	lws_pt_unlock(pt);
690 
691 try_next_dns_result_closesock:
692 	/*
693 	 * We are killing the socket but leaving
694 	 */
695 	compatible_close(wsi->desc.sockfd);
696 	wsi->desc.sockfd = LWS_SOCK_INVALID;
697 
698 try_next_dns_result:
699 	lws_sul_cancel(&wsi->sul_connect_timeout);
700 	if (lws_dll2_get_head(&wsi->dns_sorted_list))
701 		goto next_dns_result;
702 
703 	lws_addrinfo_clean(wsi);
704 	lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
705 
706 failed1:
707 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect3");
708 
709 	return NULL;
710 }
711