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