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