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