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