1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 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_cistatic int 28d4afb5ceSopenharmony_cilws_get_idlest_tsi(struct lws_context *context) 29d4afb5ceSopenharmony_ci{ 30d4afb5ceSopenharmony_ci unsigned int lowest = ~0u; 31d4afb5ceSopenharmony_ci int n = 0, hit = -1; 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ci for (; n < context->count_threads; n++) { 34d4afb5ceSopenharmony_ci lwsl_cx_debug(context, "%d %d\n", context->pt[n].fds_count, 35d4afb5ceSopenharmony_ci context->fd_limit_per_thread - 1); 36d4afb5ceSopenharmony_ci if ((unsigned int)context->pt[n].fds_count != 37d4afb5ceSopenharmony_ci context->fd_limit_per_thread - 1 && 38d4afb5ceSopenharmony_ci (unsigned int)context->pt[n].fds_count < lowest) { 39d4afb5ceSopenharmony_ci lowest = context->pt[n].fds_count; 40d4afb5ceSopenharmony_ci hit = n; 41d4afb5ceSopenharmony_ci } 42d4afb5ceSopenharmony_ci } 43d4afb5ceSopenharmony_ci 44d4afb5ceSopenharmony_ci return hit; 45d4afb5ceSopenharmony_ci} 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_cistruct lws * 48d4afb5ceSopenharmony_cilws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi, const char *desc) 49d4afb5ceSopenharmony_ci{ 50d4afb5ceSopenharmony_ci struct lws *new_wsi; 51d4afb5ceSopenharmony_ci int n = fixed_tsi; 52d4afb5ceSopenharmony_ci 53d4afb5ceSopenharmony_ci if (n < 0) 54d4afb5ceSopenharmony_ci n = lws_get_idlest_tsi(vhost->context); 55d4afb5ceSopenharmony_ci 56d4afb5ceSopenharmony_ci if (n < 0) { 57d4afb5ceSopenharmony_ci lwsl_vhost_err(vhost, "no space for new conn"); 58d4afb5ceSopenharmony_ci return NULL; 59d4afb5ceSopenharmony_ci } 60d4afb5ceSopenharmony_ci 61d4afb5ceSopenharmony_ci lws_context_lock(vhost->context, __func__); 62d4afb5ceSopenharmony_ci new_wsi = __lws_wsi_create_with_role(vhost->context, n, NULL, 63d4afb5ceSopenharmony_ci vhost->lc.log_cx); 64d4afb5ceSopenharmony_ci lws_context_unlock(vhost->context); 65d4afb5ceSopenharmony_ci if (new_wsi == NULL) { 66d4afb5ceSopenharmony_ci lwsl_vhost_err(vhost, "OOM"); 67d4afb5ceSopenharmony_ci return NULL; 68d4afb5ceSopenharmony_ci } 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ci lws_wsi_fault_timedclose(new_wsi); 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ci __lws_lc_tag(vhost->context, &vhost->context->lcg[ 73d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT) 74d4afb5ceSopenharmony_ci strcmp(desc, "adopted") ? LWSLCG_WSI_MUX : 75d4afb5ceSopenharmony_ci#endif 76d4afb5ceSopenharmony_ci LWSLCG_WSI_SERVER], &new_wsi->lc, desc); 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci new_wsi->wsistate |= LWSIFR_SERVER; 79d4afb5ceSopenharmony_ci new_wsi->tsi = (char)n; 80d4afb5ceSopenharmony_ci lwsl_wsi_debug(new_wsi, "joining vh %s, tsi %d", 81d4afb5ceSopenharmony_ci vhost->name, new_wsi->tsi); 82d4afb5ceSopenharmony_ci 83d4afb5ceSopenharmony_ci lws_vhost_bind_wsi(vhost, new_wsi); 84d4afb5ceSopenharmony_ci new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; 85d4afb5ceSopenharmony_ci new_wsi->retry_policy = vhost->retry_policy; 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci /* initialize the instance struct */ 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci lwsi_set_state(new_wsi, LRS_UNCONNECTED); 90d4afb5ceSopenharmony_ci new_wsi->hdr_parsing_completed = 0; 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_ci#ifdef LWS_WITH_TLS 93d4afb5ceSopenharmony_ci new_wsi->tls.use_ssl = LWS_SSL_ENABLED(vhost); 94d4afb5ceSopenharmony_ci#endif 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci /* 97d4afb5ceSopenharmony_ci * these can only be set once the protocol is known 98d4afb5ceSopenharmony_ci * we set an un-established connection's protocol pointer 99d4afb5ceSopenharmony_ci * to the start of the supported list, so it can look 100d4afb5ceSopenharmony_ci * for matching ones during the handshake 101d4afb5ceSopenharmony_ci */ 102d4afb5ceSopenharmony_ci new_wsi->a.protocol = vhost->protocols; 103d4afb5ceSopenharmony_ci new_wsi->user_space = NULL; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci /* 106d4afb5ceSopenharmony_ci * outermost create notification for wsi 107d4afb5ceSopenharmony_ci * no user_space because no protocol selection 108d4afb5ceSopenharmony_ci */ 109d4afb5ceSopenharmony_ci vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE, NULL, 110d4afb5ceSopenharmony_ci NULL, 0); 111d4afb5ceSopenharmony_ci 112d4afb5ceSopenharmony_ci return new_wsi; 113d4afb5ceSopenharmony_ci} 114d4afb5ceSopenharmony_ci 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci/* if not a socket, it's a raw, non-ssl file descriptor 117d4afb5ceSopenharmony_ci * req cx lock, acq pt lock, acq vh lock 118d4afb5ceSopenharmony_ci */ 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_cistatic struct lws * 121d4afb5ceSopenharmony_ci__lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type, 122d4afb5ceSopenharmony_ci const char *vh_prot_name, struct lws *parent, 123d4afb5ceSopenharmony_ci void *opaque, const char *fi_wsi_name) 124d4afb5ceSopenharmony_ci{ 125d4afb5ceSopenharmony_ci struct lws_context *context; 126d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 127d4afb5ceSopenharmony_ci struct lws *new_wsi; 128d4afb5ceSopenharmony_ci int n; 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_ci /* 131d4afb5ceSopenharmony_ci * Notice that in SMP case, the wsi may be being created on an 132d4afb5ceSopenharmony_ci * entirely different pt / tsi for load balancing. In that case as 133d4afb5ceSopenharmony_ci * we initialize it, it may become "live" concurrently unexpectedly... 134d4afb5ceSopenharmony_ci */ 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci if (!vh) 137d4afb5ceSopenharmony_ci return NULL; 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci context = vh->context; 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci lws_context_assert_lock_held(vh->context); 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci n = -1; 144d4afb5ceSopenharmony_ci if (parent) 145d4afb5ceSopenharmony_ci n = parent->tsi; 146d4afb5ceSopenharmony_ci new_wsi = lws_create_new_server_wsi(vh, n, "adopted"); 147d4afb5ceSopenharmony_ci if (!new_wsi) 148d4afb5ceSopenharmony_ci return NULL; 149d4afb5ceSopenharmony_ci 150d4afb5ceSopenharmony_ci /* bring in specific fault injection rules early */ 151d4afb5ceSopenharmony_ci lws_fi_inherit_copy(&new_wsi->fic, &context->fic, "wsi", fi_wsi_name); 152d4afb5ceSopenharmony_ci 153d4afb5ceSopenharmony_ci if (lws_fi(&new_wsi->fic, "createfail")) { 154d4afb5ceSopenharmony_ci lws_fi_destroy(&new_wsi->fic); 155d4afb5ceSopenharmony_ci 156d4afb5ceSopenharmony_ci return NULL; 157d4afb5ceSopenharmony_ci } 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci new_wsi->a.opaque_user_data = opaque; 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_ci pt = &context->pt[(int)new_wsi->tsi]; 162d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci if (parent) { 165d4afb5ceSopenharmony_ci new_wsi->parent = parent; 166d4afb5ceSopenharmony_ci new_wsi->sibling_list = parent->child_list; 167d4afb5ceSopenharmony_ci parent->child_list = new_wsi; 168d4afb5ceSopenharmony_ci } 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci if (vh_prot_name) { 171d4afb5ceSopenharmony_ci new_wsi->a.protocol = lws_vhost_name_to_protocol(new_wsi->a.vhost, 172d4afb5ceSopenharmony_ci vh_prot_name); 173d4afb5ceSopenharmony_ci if (!new_wsi->a.protocol) { 174d4afb5ceSopenharmony_ci lwsl_vhost_err(new_wsi->a.vhost, "Protocol %s not enabled", 175d4afb5ceSopenharmony_ci vh_prot_name); 176d4afb5ceSopenharmony_ci goto bail; 177d4afb5ceSopenharmony_ci } 178d4afb5ceSopenharmony_ci if (lws_ensure_user_space(new_wsi)) { 179d4afb5ceSopenharmony_ci lwsl_wsi_notice(new_wsi, "OOM"); 180d4afb5ceSopenharmony_ci goto bail; 181d4afb5ceSopenharmony_ci } 182d4afb5ceSopenharmony_ci } 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci if (!LWS_SSL_ENABLED(new_wsi->a.vhost) || 185d4afb5ceSopenharmony_ci !(type & LWS_ADOPT_SOCKET)) 186d4afb5ceSopenharmony_ci type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL; 187d4afb5ceSopenharmony_ci 188d4afb5ceSopenharmony_ci if (lws_role_call_adoption_bind(new_wsi, (int)type, vh_prot_name)) { 189d4afb5ceSopenharmony_ci lwsl_wsi_err(new_wsi, "no role for desc type 0x%x", type); 190d4afb5ceSopenharmony_ci goto bail; 191d4afb5ceSopenharmony_ci } 192d4afb5ceSopenharmony_ci 193d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 194d4afb5ceSopenharmony_ci if (new_wsi->role_ops) { 195d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(new_wsi, "role", new_wsi->role_ops->name); 196d4afb5ceSopenharmony_ci } 197d4afb5ceSopenharmony_ci#endif 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci /* 202d4afb5ceSopenharmony_ci * he's an allocated wsi, but he's not on any fds list or child list, 203d4afb5ceSopenharmony_ci * join him to the vhost's list of these kinds of incomplete wsi until 204d4afb5ceSopenharmony_ci * he gets another identity (he may do async dns now...) 205d4afb5ceSopenharmony_ci */ 206d4afb5ceSopenharmony_ci lws_vhost_lock(new_wsi->a.vhost); 207d4afb5ceSopenharmony_ci lws_dll2_add_head(&new_wsi->vh_awaiting_socket, 208d4afb5ceSopenharmony_ci &new_wsi->a.vhost->vh_awaiting_socket_owner); 209d4afb5ceSopenharmony_ci lws_vhost_unlock(new_wsi->a.vhost); 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci return new_wsi; 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_cibail: 214d4afb5ceSopenharmony_ci lwsl_wsi_notice(new_wsi, "exiting on bail"); 215d4afb5ceSopenharmony_ci if (parent) 216d4afb5ceSopenharmony_ci parent->child_list = new_wsi->sibling_list; 217d4afb5ceSopenharmony_ci if (new_wsi->user_space) 218d4afb5ceSopenharmony_ci lws_free(new_wsi->user_space); 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci lws_fi_destroy(&new_wsi->fic); 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 223d4afb5ceSopenharmony_ci __lws_vhost_unbind_wsi(new_wsi); /* req cx, acq vh lock */ 224d4afb5ceSopenharmony_ci 225d4afb5ceSopenharmony_ci lws_free(new_wsi); 226d4afb5ceSopenharmony_ci 227d4afb5ceSopenharmony_ci return NULL; 228d4afb5ceSopenharmony_ci} 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS) 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci/* 233d4afb5ceSopenharmony_ci * If the incoming wsi is bound to a vhost that is a ss server, this creates 234d4afb5ceSopenharmony_ci * an accepted ss bound to the wsi. 235d4afb5ceSopenharmony_ci * 236d4afb5ceSopenharmony_ci * For h1 or raw, we can do the binding here, but for muxed protocols like h2 237d4afb5ceSopenharmony_ci * or mqtt we have to do it not on the nwsi but on the stream. And for h2 we 238d4afb5ceSopenharmony_ci * start off bound to h1 role, since we don't know if we will upgrade to h2 239d4afb5ceSopenharmony_ci * until we meet the server. 240d4afb5ceSopenharmony_ci * 241d4afb5ceSopenharmony_ci * 1) No tls is assumed to mean no muxed protocol so can do it at adopt. 242d4afb5ceSopenharmony_ci * 243d4afb5ceSopenharmony_ci * 2) After alpn if not muxed we can do it. 244d4afb5ceSopenharmony_ci * 245d4afb5ceSopenharmony_ci * 3) For muxed, do it at the nwsi migration and on new stream 246d4afb5ceSopenharmony_ci */ 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ciint 249d4afb5ceSopenharmony_cilws_adopt_ss_server_accept(struct lws *new_wsi) 250d4afb5ceSopenharmony_ci{ 251d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = 252d4afb5ceSopenharmony_ci &new_wsi->a.context->pt[(int)new_wsi->tsi]; 253d4afb5ceSopenharmony_ci lws_ss_handle_t *h; 254d4afb5ceSopenharmony_ci void *pv, **ppv; 255d4afb5ceSopenharmony_ci 256d4afb5ceSopenharmony_ci if (!new_wsi->a.vhost->ss_handle) 257d4afb5ceSopenharmony_ci return 0; 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci pv = (char *)&new_wsi->a.vhost->ss_handle[1]; 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci /* 262d4afb5ceSopenharmony_ci * Yes... the vhost is pointing to its secure stream representing the 263d4afb5ceSopenharmony_ci * server... we want to create an accepted SS and bind it to new_wsi, 264d4afb5ceSopenharmony_ci * the info/ssi from the server SS (so the SS callbacks defined there), 265d4afb5ceSopenharmony_ci * the opaque_user_data of the server object and the policy of it. 266d4afb5ceSopenharmony_ci */ 267d4afb5ceSopenharmony_ci 268d4afb5ceSopenharmony_ci ppv = (void **)((char *)pv + 269d4afb5ceSopenharmony_ci new_wsi->a.vhost->ss_handle->info.opaque_user_data_offset); 270d4afb5ceSopenharmony_ci 271d4afb5ceSopenharmony_ci /* 272d4afb5ceSopenharmony_ci * indicate we are an accepted connection referencing the 273d4afb5ceSopenharmony_ci * server object 274d4afb5ceSopenharmony_ci */ 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci new_wsi->a.vhost->ss_handle->info.flags |= LWSSSINFLAGS_SERVER; 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci if (lws_ss_create(new_wsi->a.context, new_wsi->tsi, 279d4afb5ceSopenharmony_ci &new_wsi->a.vhost->ss_handle->info, 280d4afb5ceSopenharmony_ci *ppv, &h, NULL, NULL)) { 281d4afb5ceSopenharmony_ci lwsl_wsi_err(new_wsi, "accept ss creation failed"); 282d4afb5ceSopenharmony_ci goto fail1; 283d4afb5ceSopenharmony_ci } 284d4afb5ceSopenharmony_ci 285d4afb5ceSopenharmony_ci /* 286d4afb5ceSopenharmony_ci * We made a fresh accepted SS conn from the server pieces, 287d4afb5ceSopenharmony_ci * now bind the wsi... the problem is, this is the nwsi if it's 288d4afb5ceSopenharmony_ci * h2. 289d4afb5ceSopenharmony_ci */ 290d4afb5ceSopenharmony_ci 291d4afb5ceSopenharmony_ci h->wsi = new_wsi; 292d4afb5ceSopenharmony_ci new_wsi->a.opaque_user_data = h; 293d4afb5ceSopenharmony_ci h->info.flags |= LWSSSINFLAGS_ACCEPTED; 294d4afb5ceSopenharmony_ci /* indicate wsi should invalidate any ss link to it on close */ 295d4afb5ceSopenharmony_ci new_wsi->for_ss = 1; 296d4afb5ceSopenharmony_ci 297d4afb5ceSopenharmony_ci // lwsl_wsi_notice(new_wsi, "%s: opaq %p, role %s", 298d4afb5ceSopenharmony_ci // new_wsi->a.opaque_user_data, 299d4afb5ceSopenharmony_ci // new_wsi->role_ops->name); 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci h->policy = new_wsi->a.vhost->ss_handle->policy; 302d4afb5ceSopenharmony_ci 303d4afb5ceSopenharmony_ci /* apply requested socket options */ 304d4afb5ceSopenharmony_ci if (lws_plat_set_socket_options_ip(new_wsi->desc.sockfd, 305d4afb5ceSopenharmony_ci h->policy->priority, 306d4afb5ceSopenharmony_ci (LCCSCF_IP_LOW_LATENCY * 307d4afb5ceSopenharmony_ci !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)) | 308d4afb5ceSopenharmony_ci (LCCSCF_IP_HIGH_THROUGHPUT * 309d4afb5ceSopenharmony_ci !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)) | 310d4afb5ceSopenharmony_ci (LCCSCF_IP_HIGH_RELIABILITY * 311d4afb5ceSopenharmony_ci !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)) | 312d4afb5ceSopenharmony_ci (LCCSCF_IP_LOW_COST * 313d4afb5ceSopenharmony_ci !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_COST)))) 314d4afb5ceSopenharmony_ci lwsl_wsi_warn(new_wsi, "unable to set ip options"); 315d4afb5ceSopenharmony_ci 316d4afb5ceSopenharmony_ci /* 317d4afb5ceSopenharmony_ci * add us to the list of clients that came in from the server 318d4afb5ceSopenharmony_ci */ 319d4afb5ceSopenharmony_ci 320d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 321d4afb5ceSopenharmony_ci lws_dll2_add_tail(&h->cli_list, &new_wsi->a.vhost->ss_handle->src_list); 322d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 323d4afb5ceSopenharmony_ci 324d4afb5ceSopenharmony_ci /* 325d4afb5ceSopenharmony_ci * Let's give it appropriate state notifications 326d4afb5ceSopenharmony_ci */ 327d4afb5ceSopenharmony_ci 328d4afb5ceSopenharmony_ci if (lws_ss_event_helper(h, LWSSSCS_CREATING)) 329d4afb5ceSopenharmony_ci goto fail; 330d4afb5ceSopenharmony_ci if (lws_ss_event_helper(h, LWSSSCS_CONNECTING)) 331d4afb5ceSopenharmony_ci goto fail; 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_ci /* defer CONNECTED until we see if he is upgrading */ 334d4afb5ceSopenharmony_ci 335d4afb5ceSopenharmony_ci// if (lws_ss_event_helper(h, LWSSSCS_CONNECTED)) 336d4afb5ceSopenharmony_ci// goto fail; 337d4afb5ceSopenharmony_ci 338d4afb5ceSopenharmony_ci // lwsl_notice("%s: accepted ss complete, pcol %s\n", __func__, 339d4afb5ceSopenharmony_ci // new_wsi->a.protocol->name); 340d4afb5ceSopenharmony_ci 341d4afb5ceSopenharmony_ci return 0; 342d4afb5ceSopenharmony_ci 343d4afb5ceSopenharmony_cifail: 344d4afb5ceSopenharmony_ci lws_ss_destroy(&h); 345d4afb5ceSopenharmony_cifail1: 346d4afb5ceSopenharmony_ci return 1; 347d4afb5ceSopenharmony_ci} 348d4afb5ceSopenharmony_ci 349d4afb5ceSopenharmony_ci#endif 350d4afb5ceSopenharmony_ci 351d4afb5ceSopenharmony_ci 352d4afb5ceSopenharmony_cistatic struct lws * 353d4afb5ceSopenharmony_cilws_adopt_descriptor_vhost2(struct lws *new_wsi, lws_adoption_type type, 354d4afb5ceSopenharmony_ci lws_sock_file_fd_type fd) 355d4afb5ceSopenharmony_ci{ 356d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = 357d4afb5ceSopenharmony_ci &new_wsi->a.context->pt[(int)new_wsi->tsi]; 358d4afb5ceSopenharmony_ci int n; 359d4afb5ceSopenharmony_ci 360d4afb5ceSopenharmony_ci /* enforce that every fd is nonblocking */ 361d4afb5ceSopenharmony_ci 362d4afb5ceSopenharmony_ci if (type & LWS_ADOPT_SOCKET) { 363d4afb5ceSopenharmony_ci if (lws_plat_set_nonblocking(fd.sockfd)) { 364d4afb5ceSopenharmony_ci lwsl_wsi_err(new_wsi, "unable to set sockfd %d nonblocking", 365d4afb5ceSopenharmony_ci fd.sockfd); 366d4afb5ceSopenharmony_ci goto fail; 367d4afb5ceSopenharmony_ci } 368d4afb5ceSopenharmony_ci } 369d4afb5ceSopenharmony_ci#if !defined(WIN32) 370d4afb5ceSopenharmony_ci else 371d4afb5ceSopenharmony_ci if (lws_plat_set_nonblocking(fd.filefd)) { 372d4afb5ceSopenharmony_ci lwsl_wsi_err(new_wsi, "unable to set filefd nonblocking"); 373d4afb5ceSopenharmony_ci goto fail; 374d4afb5ceSopenharmony_ci } 375d4afb5ceSopenharmony_ci#endif 376d4afb5ceSopenharmony_ci 377d4afb5ceSopenharmony_ci new_wsi->desc = fd; 378d4afb5ceSopenharmony_ci 379d4afb5ceSopenharmony_ci if (!LWS_SSL_ENABLED(new_wsi->a.vhost) || 380d4afb5ceSopenharmony_ci !(type & LWS_ADOPT_SOCKET)) 381d4afb5ceSopenharmony_ci type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL; 382d4afb5ceSopenharmony_ci 383d4afb5ceSopenharmony_ci /* 384d4afb5ceSopenharmony_ci * A new connection was accepted. Give the user a chance to 385d4afb5ceSopenharmony_ci * set properties of the newly created wsi. There's no protocol 386d4afb5ceSopenharmony_ci * selected yet so we issue this to the vhosts's default protocol, 387d4afb5ceSopenharmony_ci * itself by default protocols[0] 388d4afb5ceSopenharmony_ci */ 389d4afb5ceSopenharmony_ci new_wsi->wsistate |= LWSIFR_SERVER; 390d4afb5ceSopenharmony_ci n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED; 391d4afb5ceSopenharmony_ci if (new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)]) 392d4afb5ceSopenharmony_ci n = new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)]; 393d4afb5ceSopenharmony_ci 394d4afb5ceSopenharmony_ci if (new_wsi->a.context->event_loop_ops->sock_accept) 395d4afb5ceSopenharmony_ci if (new_wsi->a.context->event_loop_ops->sock_accept(new_wsi)) 396d4afb5ceSopenharmony_ci goto fail; 397d4afb5ceSopenharmony_ci 398d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1 399d4afb5ceSopenharmony_ci /* 400d4afb5ceSopenharmony_ci * Caution: after this point the wsi is live on its service thread 401d4afb5ceSopenharmony_ci * which may be concurrent to this. We mark the wsi as still undergoing 402d4afb5ceSopenharmony_ci * init in another pt so the assigned pt leaves it alone. 403d4afb5ceSopenharmony_ci */ 404d4afb5ceSopenharmony_ci new_wsi->undergoing_init_from_other_pt = 1; 405d4afb5ceSopenharmony_ci#endif 406d4afb5ceSopenharmony_ci 407d4afb5ceSopenharmony_ci if (!(type & LWS_ADOPT_ALLOW_SSL)) { 408d4afb5ceSopenharmony_ci lws_pt_lock(pt, __func__); 409d4afb5ceSopenharmony_ci if (__insert_wsi_socket_into_fds(new_wsi->a.context, new_wsi)) { 410d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 411d4afb5ceSopenharmony_ci lwsl_wsi_err(new_wsi, "fail inserting socket"); 412d4afb5ceSopenharmony_ci goto fail; 413d4afb5ceSopenharmony_ci } 414d4afb5ceSopenharmony_ci lws_pt_unlock(pt); 415d4afb5ceSopenharmony_ci } 416d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 417d4afb5ceSopenharmony_ci else 418d4afb5ceSopenharmony_ci if (lws_server_socket_service_ssl(new_wsi, fd.sockfd, 0)) { 419d4afb5ceSopenharmony_ci lwsl_wsi_info(new_wsi, "fail ssl negotiation"); 420d4afb5ceSopenharmony_ci 421d4afb5ceSopenharmony_ci goto fail; 422d4afb5ceSopenharmony_ci } 423d4afb5ceSopenharmony_ci#endif 424d4afb5ceSopenharmony_ci 425d4afb5ceSopenharmony_ci lws_vhost_lock(new_wsi->a.vhost); 426d4afb5ceSopenharmony_ci /* he has fds visibility now, remove from vhost orphan list */ 427d4afb5ceSopenharmony_ci lws_dll2_remove(&new_wsi->vh_awaiting_socket); 428d4afb5ceSopenharmony_ci lws_vhost_unlock(new_wsi->a.vhost); 429d4afb5ceSopenharmony_ci 430d4afb5ceSopenharmony_ci /* 431d4afb5ceSopenharmony_ci * by deferring callback to this point, after insertion to fds, 432d4afb5ceSopenharmony_ci * lws_callback_on_writable() can work from the callback 433d4afb5ceSopenharmony_ci */ 434d4afb5ceSopenharmony_ci if ((new_wsi->a.protocol->callback)(new_wsi, (enum lws_callback_reasons)n, new_wsi->user_space, 435d4afb5ceSopenharmony_ci NULL, 0)) 436d4afb5ceSopenharmony_ci goto fail; 437d4afb5ceSopenharmony_ci 438d4afb5ceSopenharmony_ci /* role may need to do something after all adoption completed */ 439d4afb5ceSopenharmony_ci 440d4afb5ceSopenharmony_ci lws_role_call_adoption_bind(new_wsi, (int)type | _LWS_ADOPT_FINISH, 441d4afb5ceSopenharmony_ci new_wsi->a.protocol->name); 442d4afb5ceSopenharmony_ci 443d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS) 444d4afb5ceSopenharmony_ci /* 445d4afb5ceSopenharmony_ci * Did we come from an accepted client connection to a ss server? 446d4afb5ceSopenharmony_ci * 447d4afb5ceSopenharmony_ci * !!! For mux protocols, this will cause an additional inactive ss 448d4afb5ceSopenharmony_ci * representing the nwsi. Doing that allows us to support both h1 449d4afb5ceSopenharmony_ci * (here) and h2 (at __lws_wsi_server_new()) 450d4afb5ceSopenharmony_ci */ 451d4afb5ceSopenharmony_ci 452d4afb5ceSopenharmony_ci lwsl_wsi_info(new_wsi, "vhost %s", new_wsi->a.vhost->lc.gutag); 453d4afb5ceSopenharmony_ci 454d4afb5ceSopenharmony_ci if (lws_adopt_ss_server_accept(new_wsi)) 455d4afb5ceSopenharmony_ci goto fail; 456d4afb5ceSopenharmony_ci#endif 457d4afb5ceSopenharmony_ci 458d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1 459d4afb5ceSopenharmony_ci /* its actual pt can service it now */ 460d4afb5ceSopenharmony_ci 461d4afb5ceSopenharmony_ci new_wsi->undergoing_init_from_other_pt = 0; 462d4afb5ceSopenharmony_ci#endif 463d4afb5ceSopenharmony_ci 464d4afb5ceSopenharmony_ci lws_cancel_service_pt(new_wsi); 465d4afb5ceSopenharmony_ci 466d4afb5ceSopenharmony_ci return new_wsi; 467d4afb5ceSopenharmony_ci 468d4afb5ceSopenharmony_cifail: 469d4afb5ceSopenharmony_ci if (type & LWS_ADOPT_SOCKET) 470d4afb5ceSopenharmony_ci lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS, 471d4afb5ceSopenharmony_ci "adopt skt fail"); 472d4afb5ceSopenharmony_ci 473d4afb5ceSopenharmony_ci return NULL; 474d4afb5ceSopenharmony_ci} 475d4afb5ceSopenharmony_ci 476d4afb5ceSopenharmony_ci 477d4afb5ceSopenharmony_ci/* if not a socket, it's a raw, non-ssl file descriptor */ 478d4afb5ceSopenharmony_ci 479d4afb5ceSopenharmony_cistruct lws * 480d4afb5ceSopenharmony_cilws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, 481d4afb5ceSopenharmony_ci lws_sock_file_fd_type fd, const char *vh_prot_name, 482d4afb5ceSopenharmony_ci struct lws *parent) 483d4afb5ceSopenharmony_ci{ 484d4afb5ceSopenharmony_ci lws_adopt_desc_t info; 485d4afb5ceSopenharmony_ci 486d4afb5ceSopenharmony_ci memset(&info, 0, sizeof(info)); 487d4afb5ceSopenharmony_ci 488d4afb5ceSopenharmony_ci info.vh = vh; 489d4afb5ceSopenharmony_ci info.type = type; 490d4afb5ceSopenharmony_ci info.fd = fd; 491d4afb5ceSopenharmony_ci info.vh_prot_name = vh_prot_name; 492d4afb5ceSopenharmony_ci info.parent = parent; 493d4afb5ceSopenharmony_ci 494d4afb5ceSopenharmony_ci return lws_adopt_descriptor_vhost_via_info(&info); 495d4afb5ceSopenharmony_ci} 496d4afb5ceSopenharmony_ci 497d4afb5ceSopenharmony_cistruct lws * 498d4afb5ceSopenharmony_cilws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info) 499d4afb5ceSopenharmony_ci{ 500d4afb5ceSopenharmony_ci socklen_t slen = sizeof(lws_sockaddr46); 501d4afb5ceSopenharmony_ci struct lws *new_wsi; 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) 504d4afb5ceSopenharmony_ci struct lws_peer *peer = NULL; 505d4afb5ceSopenharmony_ci 506d4afb5ceSopenharmony_ci if (info->type & LWS_ADOPT_SOCKET) { 507d4afb5ceSopenharmony_ci peer = lws_get_or_create_peer(info->vh, info->fd.sockfd); 508d4afb5ceSopenharmony_ci 509d4afb5ceSopenharmony_ci if (peer && info->vh->context->ip_limit_wsi && 510d4afb5ceSopenharmony_ci peer->count_wsi >= info->vh->context->ip_limit_wsi) { 511d4afb5ceSopenharmony_ci lwsl_info("Peer reached wsi limit %d\n", 512d4afb5ceSopenharmony_ci info->vh->context->ip_limit_wsi); 513d4afb5ceSopenharmony_ci if (info->vh->context->pl_notify_cb) 514d4afb5ceSopenharmony_ci info->vh->context->pl_notify_cb( 515d4afb5ceSopenharmony_ci info->vh->context, 516d4afb5ceSopenharmony_ci info->fd.sockfd, 517d4afb5ceSopenharmony_ci &peer->sa46); 518d4afb5ceSopenharmony_ci compatible_close(info->fd.sockfd); 519d4afb5ceSopenharmony_ci return NULL; 520d4afb5ceSopenharmony_ci } 521d4afb5ceSopenharmony_ci } 522d4afb5ceSopenharmony_ci#endif 523d4afb5ceSopenharmony_ci 524d4afb5ceSopenharmony_ci lws_context_lock(info->vh->context, __func__); 525d4afb5ceSopenharmony_ci 526d4afb5ceSopenharmony_ci new_wsi = __lws_adopt_descriptor_vhost1(info->vh, info->type, 527d4afb5ceSopenharmony_ci info->vh_prot_name, info->parent, 528d4afb5ceSopenharmony_ci info->opaque, info->fi_wsi_name); 529d4afb5ceSopenharmony_ci if (!new_wsi) { 530d4afb5ceSopenharmony_ci if (info->type & LWS_ADOPT_SOCKET) 531d4afb5ceSopenharmony_ci compatible_close(info->fd.sockfd); 532d4afb5ceSopenharmony_ci goto bail; 533d4afb5ceSopenharmony_ci } 534d4afb5ceSopenharmony_ci 535d4afb5ceSopenharmony_ci if (info->type & LWS_ADOPT_SOCKET && 536d4afb5ceSopenharmony_ci getpeername(info->fd.sockfd, (struct sockaddr *)&new_wsi->sa46_peer, 537d4afb5ceSopenharmony_ci &slen) < 0) 538d4afb5ceSopenharmony_ci lwsl_info("%s: getpeername failed\n", __func__); 539d4afb5ceSopenharmony_ci 540d4afb5ceSopenharmony_ci#if defined(LWS_WITH_PEER_LIMITS) 541d4afb5ceSopenharmony_ci if (peer) 542d4afb5ceSopenharmony_ci lws_peer_add_wsi(info->vh->context, peer, new_wsi); 543d4afb5ceSopenharmony_ci#endif 544d4afb5ceSopenharmony_ci 545d4afb5ceSopenharmony_ci new_wsi = lws_adopt_descriptor_vhost2(new_wsi, info->type, info->fd); 546d4afb5ceSopenharmony_ci 547d4afb5ceSopenharmony_cibail: 548d4afb5ceSopenharmony_ci lws_context_unlock(info->vh->context); 549d4afb5ceSopenharmony_ci 550d4afb5ceSopenharmony_ci return new_wsi; 551d4afb5ceSopenharmony_ci} 552d4afb5ceSopenharmony_ci 553d4afb5ceSopenharmony_cistruct lws * 554d4afb5ceSopenharmony_cilws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd) 555d4afb5ceSopenharmony_ci{ 556d4afb5ceSopenharmony_ci lws_sock_file_fd_type fd; 557d4afb5ceSopenharmony_ci 558d4afb5ceSopenharmony_ci fd.sockfd = accept_fd; 559d4afb5ceSopenharmony_ci return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET | 560d4afb5ceSopenharmony_ci LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL); 561d4afb5ceSopenharmony_ci} 562d4afb5ceSopenharmony_ci 563d4afb5ceSopenharmony_cistruct lws * 564d4afb5ceSopenharmony_cilws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd) 565d4afb5ceSopenharmony_ci{ 566d4afb5ceSopenharmony_ci return lws_adopt_socket_vhost(context->vhost_list, accept_fd); 567d4afb5ceSopenharmony_ci} 568d4afb5ceSopenharmony_ci 569d4afb5ceSopenharmony_ci/* Common read-buffer adoption for lws_adopt_*_readbuf */ 570d4afb5ceSopenharmony_cistatic struct lws* 571d4afb5ceSopenharmony_ciadopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len) 572d4afb5ceSopenharmony_ci{ 573d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt; 574d4afb5ceSopenharmony_ci struct lws_pollfd *pfd; 575d4afb5ceSopenharmony_ci int n; 576d4afb5ceSopenharmony_ci 577d4afb5ceSopenharmony_ci if (!wsi) 578d4afb5ceSopenharmony_ci return NULL; 579d4afb5ceSopenharmony_ci 580d4afb5ceSopenharmony_ci if (!readbuf || len == 0) 581d4afb5ceSopenharmony_ci return wsi; 582d4afb5ceSopenharmony_ci 583d4afb5ceSopenharmony_ci if (wsi->position_in_fds_table == LWS_NO_FDS_POS) 584d4afb5ceSopenharmony_ci return wsi; 585d4afb5ceSopenharmony_ci 586d4afb5ceSopenharmony_ci pt = &wsi->a.context->pt[(int)wsi->tsi]; 587d4afb5ceSopenharmony_ci 588d4afb5ceSopenharmony_ci n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf, 589d4afb5ceSopenharmony_ci len); 590d4afb5ceSopenharmony_ci if (n < 0) 591d4afb5ceSopenharmony_ci goto bail; 592d4afb5ceSopenharmony_ci if (n) 593d4afb5ceSopenharmony_ci lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner); 594d4afb5ceSopenharmony_ci 595d4afb5ceSopenharmony_ci /* 596d4afb5ceSopenharmony_ci * we can't process the initial read data until we can attach an ah. 597d4afb5ceSopenharmony_ci * 598d4afb5ceSopenharmony_ci * if one is available, get it and place the data in his ah rxbuf... 599d4afb5ceSopenharmony_ci * wsi with ah that have pending rxbuf get auto-POLLIN service. 600d4afb5ceSopenharmony_ci * 601d4afb5ceSopenharmony_ci * no autoservice because we didn't get a chance to attach the 602d4afb5ceSopenharmony_ci * readbuf data to wsi or ah yet, and we will do it next if we get 603d4afb5ceSopenharmony_ci * the ah. 604d4afb5ceSopenharmony_ci */ 605d4afb5ceSopenharmony_ci if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) { 606d4afb5ceSopenharmony_ci 607d4afb5ceSopenharmony_ci lwsl_notice("%s: calling service on readbuf ah\n", __func__); 608d4afb5ceSopenharmony_ci 609d4afb5ceSopenharmony_ci /* 610d4afb5ceSopenharmony_ci * unlike a normal connect, we have the headers already 611d4afb5ceSopenharmony_ci * (or the first part of them anyway). 612d4afb5ceSopenharmony_ci * libuv won't come back and service us without a network 613d4afb5ceSopenharmony_ci * event, so we need to do the header service right here. 614d4afb5ceSopenharmony_ci */ 615d4afb5ceSopenharmony_ci pfd = &pt->fds[wsi->position_in_fds_table]; 616d4afb5ceSopenharmony_ci pfd->revents |= LWS_POLLIN; 617d4afb5ceSopenharmony_ci lwsl_err("%s: calling service\n", __func__); 618d4afb5ceSopenharmony_ci if (lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi)) 619d4afb5ceSopenharmony_ci /* service closed us */ 620d4afb5ceSopenharmony_ci return NULL; 621d4afb5ceSopenharmony_ci 622d4afb5ceSopenharmony_ci return wsi; 623d4afb5ceSopenharmony_ci } 624d4afb5ceSopenharmony_ci lwsl_err("%s: deferring handling ah\n", __func__); 625d4afb5ceSopenharmony_ci 626d4afb5ceSopenharmony_ci return wsi; 627d4afb5ceSopenharmony_ci 628d4afb5ceSopenharmony_cibail: 629d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, 630d4afb5ceSopenharmony_ci "adopt skt readbuf fail"); 631d4afb5ceSopenharmony_ci 632d4afb5ceSopenharmony_ci return NULL; 633d4afb5ceSopenharmony_ci} 634d4afb5ceSopenharmony_ci 635d4afb5ceSopenharmony_ci#if defined(LWS_WITH_UDP) 636d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT) 637d4afb5ceSopenharmony_ci 638d4afb5ceSopenharmony_ci/* 639d4afb5ceSopenharmony_ci * This is the ASYNC_DNS callback target for udp client, it's analogous to 640d4afb5ceSopenharmony_ci * connect3() 641d4afb5ceSopenharmony_ci */ 642d4afb5ceSopenharmony_ci 643d4afb5ceSopenharmony_cistatic struct lws * 644d4afb5ceSopenharmony_cilws_create_adopt_udp2(struct lws *wsi, const char *ads, 645d4afb5ceSopenharmony_ci const struct addrinfo *r, int n, void *opaque) 646d4afb5ceSopenharmony_ci{ 647d4afb5ceSopenharmony_ci lws_sock_file_fd_type sock; 648d4afb5ceSopenharmony_ci int bc = 1, m; 649d4afb5ceSopenharmony_ci 650d4afb5ceSopenharmony_ci assert(wsi); 651d4afb5ceSopenharmony_ci 652d4afb5ceSopenharmony_ci if (ads && (n < 0 || !r)) { 653d4afb5ceSopenharmony_ci /* 654d4afb5ceSopenharmony_ci * DNS lookup failed: there are no usable results. Fail the 655d4afb5ceSopenharmony_ci * overall connection request. 656d4afb5ceSopenharmony_ci */ 657d4afb5ceSopenharmony_ci lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r); 658d4afb5ceSopenharmony_ci 659d4afb5ceSopenharmony_ci goto bail; 660d4afb5ceSopenharmony_ci } 661d4afb5ceSopenharmony_ci 662d4afb5ceSopenharmony_ci m = lws_sort_dns(wsi, r); 663d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS) 664d4afb5ceSopenharmony_ci lws_async_dns_freeaddrinfo(&r); 665d4afb5ceSopenharmony_ci#else 666d4afb5ceSopenharmony_ci freeaddrinfo((struct addrinfo *)r); 667d4afb5ceSopenharmony_ci#endif 668d4afb5ceSopenharmony_ci if (m) 669d4afb5ceSopenharmony_ci goto bail; 670d4afb5ceSopenharmony_ci 671d4afb5ceSopenharmony_ci while (lws_dll2_get_head(&wsi->dns_sorted_list)) { 672d4afb5ceSopenharmony_ci lws_dns_sort_t *s = lws_container_of( 673d4afb5ceSopenharmony_ci lws_dll2_get_head(&wsi->dns_sorted_list), 674d4afb5ceSopenharmony_ci lws_dns_sort_t, list); 675d4afb5ceSopenharmony_ci 676d4afb5ceSopenharmony_ci /* 677d4afb5ceSopenharmony_ci * Remove it from the head, but don't free it yet... we are 678d4afb5ceSopenharmony_ci * taking responsibility to free it 679d4afb5ceSopenharmony_ci */ 680d4afb5ceSopenharmony_ci lws_dll2_remove(&s->list); 681d4afb5ceSopenharmony_ci 682d4afb5ceSopenharmony_ci /* 683d4afb5ceSopenharmony_ci * We have done the dns lookup, identify the result we want 684d4afb5ceSopenharmony_ci * if any, and then complete the adoption by binding wsi to 685d4afb5ceSopenharmony_ci * socket opened on it. 686d4afb5ceSopenharmony_ci * 687d4afb5ceSopenharmony_ci * Ignore the weak assumptions about protocol driven by port 688d4afb5ceSopenharmony_ci * number and force to DGRAM / UDP since that's what this 689d4afb5ceSopenharmony_ci * function is for. 690d4afb5ceSopenharmony_ci */ 691d4afb5ceSopenharmony_ci 692d4afb5ceSopenharmony_ci#if !defined(__linux__) 693d4afb5ceSopenharmony_ci sock.sockfd = socket(s->dest.sa4.sin_family, 694d4afb5ceSopenharmony_ci SOCK_DGRAM, IPPROTO_UDP); 695d4afb5ceSopenharmony_ci#else 696d4afb5ceSopenharmony_ci /* PF_PACKET is linux-only */ 697d4afb5ceSopenharmony_ci sock.sockfd = socket(wsi->pf_packet ? PF_PACKET : 698d4afb5ceSopenharmony_ci s->dest.sa4.sin_family, 699d4afb5ceSopenharmony_ci SOCK_DGRAM, wsi->pf_packet ? 700d4afb5ceSopenharmony_ci htons(0x800) : IPPROTO_UDP); 701d4afb5ceSopenharmony_ci#endif 702d4afb5ceSopenharmony_ci if (sock.sockfd == LWS_SOCK_INVALID) 703d4afb5ceSopenharmony_ci goto resume; 704d4afb5ceSopenharmony_ci 705d4afb5ceSopenharmony_ci /* ipv6 udp!!! */ 706d4afb5ceSopenharmony_ci 707d4afb5ceSopenharmony_ci if (s->af == AF_INET) 708d4afb5ceSopenharmony_ci s->dest.sa4.sin_port = htons(wsi->c_port); 709d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 710d4afb5ceSopenharmony_ci else 711d4afb5ceSopenharmony_ci s->dest.sa6.sin6_port = htons(wsi->c_port); 712d4afb5ceSopenharmony_ci#endif 713d4afb5ceSopenharmony_ci 714d4afb5ceSopenharmony_ci if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR, 715d4afb5ceSopenharmony_ci (const char *)&bc, sizeof(bc)) < 0) 716d4afb5ceSopenharmony_ci lwsl_err("%s: failed to set reuse\n", __func__); 717d4afb5ceSopenharmony_ci 718d4afb5ceSopenharmony_ci if (wsi->do_broadcast && 719d4afb5ceSopenharmony_ci setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST, 720d4afb5ceSopenharmony_ci (const char *)&bc, sizeof(bc)) < 0) 721d4afb5ceSopenharmony_ci lwsl_err("%s: failed to set broadcast\n", __func__); 722d4afb5ceSopenharmony_ci 723d4afb5ceSopenharmony_ci /* Bind the udp socket to a particular network interface */ 724d4afb5ceSopenharmony_ci 725d4afb5ceSopenharmony_ci if (opaque && 726d4afb5ceSopenharmony_ci lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque)) 727d4afb5ceSopenharmony_ci goto resume; 728d4afb5ceSopenharmony_ci 729d4afb5ceSopenharmony_ci if (wsi->do_bind && 730d4afb5ceSopenharmony_ci bind(sock.sockfd, sa46_sockaddr(&s->dest), 731d4afb5ceSopenharmony_ci#if defined(_WIN32) 732d4afb5ceSopenharmony_ci (int)sa46_socklen(&s->dest) 733d4afb5ceSopenharmony_ci#else 734d4afb5ceSopenharmony_ci sizeof(struct sockaddr) 735d4afb5ceSopenharmony_ci#endif 736d4afb5ceSopenharmony_ci ) == -1) { 737d4afb5ceSopenharmony_ci lwsl_err("%s: bind failed\n", __func__); 738d4afb5ceSopenharmony_ci goto resume; 739d4afb5ceSopenharmony_ci } 740d4afb5ceSopenharmony_ci 741d4afb5ceSopenharmony_ci if (!wsi->do_bind && !wsi->pf_packet) { 742d4afb5ceSopenharmony_ci#if !defined(__APPLE__) 743d4afb5ceSopenharmony_ci if (connect(sock.sockfd, sa46_sockaddr(&s->dest), 744d4afb5ceSopenharmony_ci sa46_socklen(&s->dest)) == -1 && 745d4afb5ceSopenharmony_ci errno != EADDRNOTAVAIL /* openbsd */ ) { 746d4afb5ceSopenharmony_ci lwsl_err("%s: conn fd %d fam %d %s:%u failed " 747d4afb5ceSopenharmony_ci "errno %d\n", __func__, sock.sockfd, 748d4afb5ceSopenharmony_ci s->dest.sa4.sin_family, 749d4afb5ceSopenharmony_ci ads ? ads : "null", wsi->c_port, 750d4afb5ceSopenharmony_ci LWS_ERRNO); 751d4afb5ceSopenharmony_ci compatible_close(sock.sockfd); 752d4afb5ceSopenharmony_ci goto resume; 753d4afb5ceSopenharmony_ci } 754d4afb5ceSopenharmony_ci#endif 755d4afb5ceSopenharmony_ci } 756d4afb5ceSopenharmony_ci 757d4afb5ceSopenharmony_ci if (wsi->udp) 758d4afb5ceSopenharmony_ci wsi->udp->sa46 = s->dest; 759d4afb5ceSopenharmony_ci wsi->sa46_peer = s->dest; 760d4afb5ceSopenharmony_ci 761d4afb5ceSopenharmony_ci /* we connected: complete the udp socket adoption flow */ 762d4afb5ceSopenharmony_ci 763d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS) 764d4afb5ceSopenharmony_ci if (wsi->a.context->async_dns.wsi == wsi) 765d4afb5ceSopenharmony_ci wsi->a.context->async_dns.dns_server_connected = 1; 766d4afb5ceSopenharmony_ci#endif 767d4afb5ceSopenharmony_ci 768d4afb5ceSopenharmony_ci lws_free(s); 769d4afb5ceSopenharmony_ci lws_addrinfo_clean(wsi); 770d4afb5ceSopenharmony_ci return lws_adopt_descriptor_vhost2(wsi, 771d4afb5ceSopenharmony_ci LWS_ADOPT_RAW_SOCKET_UDP, sock); 772d4afb5ceSopenharmony_ci 773d4afb5ceSopenharmony_ciresume: 774d4afb5ceSopenharmony_ci lws_free(s); 775d4afb5ceSopenharmony_ci } 776d4afb5ceSopenharmony_ci 777d4afb5ceSopenharmony_ci lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO); 778d4afb5ceSopenharmony_ci lws_addrinfo_clean(wsi); 779d4afb5ceSopenharmony_ci 780d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_ASYNC_DNS) 781d4afb5ceSopenharmony_ci if (wsi->a.context->async_dns.wsi == wsi) 782d4afb5ceSopenharmony_ci lws_async_dns_drop_server(wsi->a.context); 783d4afb5ceSopenharmony_ci#endif 784d4afb5ceSopenharmony_ci 785d4afb5ceSopenharmony_cibail: 786d4afb5ceSopenharmony_ci 787d4afb5ceSopenharmony_ci /* caller must close */ 788d4afb5ceSopenharmony_ci 789d4afb5ceSopenharmony_ci return NULL; 790d4afb5ceSopenharmony_ci} 791d4afb5ceSopenharmony_ci 792d4afb5ceSopenharmony_cistruct lws * 793d4afb5ceSopenharmony_cilws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port, 794d4afb5ceSopenharmony_ci int flags, const char *protocol_name, const char *ifname, 795d4afb5ceSopenharmony_ci struct lws *parent_wsi, void *opaque, 796d4afb5ceSopenharmony_ci const lws_retry_bo_t *retry_policy, const char *fi_wsi_name) 797d4afb5ceSopenharmony_ci{ 798d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) 799d4afb5ceSopenharmony_ci struct lws *wsi; 800d4afb5ceSopenharmony_ci int n; 801d4afb5ceSopenharmony_ci 802d4afb5ceSopenharmony_ci lwsl_info("%s: %s:%u\n", __func__, ads ? ads : "null", port); 803d4afb5ceSopenharmony_ci 804d4afb5ceSopenharmony_ci /* create the logical wsi without any valid fd */ 805d4afb5ceSopenharmony_ci 806d4afb5ceSopenharmony_ci lws_context_lock(vhost->context, __func__); 807d4afb5ceSopenharmony_ci 808d4afb5ceSopenharmony_ci wsi = __lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_SOCKET | 809d4afb5ceSopenharmony_ci LWS_ADOPT_RAW_SOCKET_UDP, 810d4afb5ceSopenharmony_ci protocol_name, parent_wsi, opaque, 811d4afb5ceSopenharmony_ci fi_wsi_name); 812d4afb5ceSopenharmony_ci 813d4afb5ceSopenharmony_ci lws_context_unlock(vhost->context); 814d4afb5ceSopenharmony_ci if (!wsi) { 815d4afb5ceSopenharmony_ci lwsl_err("%s: udp wsi creation failed\n", __func__); 816d4afb5ceSopenharmony_ci goto bail; 817d4afb5ceSopenharmony_ci } 818d4afb5ceSopenharmony_ci 819d4afb5ceSopenharmony_ci // lwsl_notice("%s: role %s\n", __func__, wsi->role_ops->name); 820d4afb5ceSopenharmony_ci 821d4afb5ceSopenharmony_ci wsi->do_bind = !!(flags & LWS_CAUDP_BIND); 822d4afb5ceSopenharmony_ci wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST); 823d4afb5ceSopenharmony_ci wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET); 824d4afb5ceSopenharmony_ci wsi->c_port = (uint16_t)(unsigned int)port; 825d4afb5ceSopenharmony_ci if (retry_policy) 826d4afb5ceSopenharmony_ci wsi->retry_policy = retry_policy; 827d4afb5ceSopenharmony_ci else 828d4afb5ceSopenharmony_ci wsi->retry_policy = vhost->retry_policy; 829d4afb5ceSopenharmony_ci 830d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_SYS_ASYNC_DNS) 831d4afb5ceSopenharmony_ci { 832d4afb5ceSopenharmony_ci struct addrinfo *r, h; 833d4afb5ceSopenharmony_ci char buf[16]; 834d4afb5ceSopenharmony_ci 835d4afb5ceSopenharmony_ci memset(&h, 0, sizeof(h)); 836d4afb5ceSopenharmony_ci h.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ 837d4afb5ceSopenharmony_ci h.ai_socktype = SOCK_DGRAM; 838d4afb5ceSopenharmony_ci h.ai_protocol = IPPROTO_UDP; 839d4afb5ceSopenharmony_ci#if defined(AI_PASSIVE) 840d4afb5ceSopenharmony_ci h.ai_flags = AI_PASSIVE; 841d4afb5ceSopenharmony_ci#endif 842d4afb5ceSopenharmony_ci#ifdef AI_ADDRCONFIG 843d4afb5ceSopenharmony_ci h.ai_flags |= AI_ADDRCONFIG; 844d4afb5ceSopenharmony_ci#endif 845d4afb5ceSopenharmony_ci 846d4afb5ceSopenharmony_ci /* if the dns lookup is synchronous, do the whole thing now */ 847d4afb5ceSopenharmony_ci lws_snprintf(buf, sizeof(buf), "%u", port); 848d4afb5ceSopenharmony_ci n = getaddrinfo(ads, buf, &h, &r); 849d4afb5ceSopenharmony_ci if (n) { 850d4afb5ceSopenharmony_ci 851d4afb5ceSopenharmony_ci#if (_LWS_ENABLED_LOGS & LLL_INFO) 852d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_FREERTOS) 853d4afb5ceSopenharmony_ci lwsl_info("%s: getaddrinfo error: %s\n", __func__, 854d4afb5ceSopenharmony_ci gai_strerror(n)); 855d4afb5ceSopenharmony_ci#else 856d4afb5ceSopenharmony_ci 857d4afb5ceSopenharmony_ci lwsl_info("%s: getaddrinfo error: %s\n", __func__, 858d4afb5ceSopenharmony_ci strerror(n)); 859d4afb5ceSopenharmony_ci#endif 860d4afb5ceSopenharmony_ci#endif 861d4afb5ceSopenharmony_ci //freeaddrinfo(r); 862d4afb5ceSopenharmony_ci goto bail1; 863d4afb5ceSopenharmony_ci } 864d4afb5ceSopenharmony_ci /* 865d4afb5ceSopenharmony_ci * With synchronous dns, complete it immediately after the 866d4afb5ceSopenharmony_ci * blocking dns lookup finished... free r when connect either 867d4afb5ceSopenharmony_ci * completed or failed 868d4afb5ceSopenharmony_ci */ 869d4afb5ceSopenharmony_ci wsi = lws_create_adopt_udp2(wsi, ads, r, 0, NULL); 870d4afb5ceSopenharmony_ci 871d4afb5ceSopenharmony_ci return wsi; 872d4afb5ceSopenharmony_ci } 873d4afb5ceSopenharmony_ci#else 874d4afb5ceSopenharmony_ci if (ads) { 875d4afb5ceSopenharmony_ci /* 876d4afb5ceSopenharmony_ci * with async dns, use the wsi as the point about which to do 877d4afb5ceSopenharmony_ci * the dns lookup and have it call the second part when it's 878d4afb5ceSopenharmony_ci * done. 879d4afb5ceSopenharmony_ci * 880d4afb5ceSopenharmony_ci * Keep a refcount on the results and free it when we connected 881d4afb5ceSopenharmony_ci * or definitively failed. 882d4afb5ceSopenharmony_ci * 883d4afb5ceSopenharmony_ci * Notice wsi has no socket at this point (we don't know what 884d4afb5ceSopenharmony_ci * kind to ask for until we get the dns back). But it is bound 885d4afb5ceSopenharmony_ci * to a vhost and can be cleaned up from that at vhost destroy. 886d4afb5ceSopenharmony_ci */ 887d4afb5ceSopenharmony_ci n = lws_async_dns_query(vhost->context, 0, ads, 888d4afb5ceSopenharmony_ci LWS_ADNS_RECORD_A, 889d4afb5ceSopenharmony_ci lws_create_adopt_udp2, wsi, 890d4afb5ceSopenharmony_ci (void *)ifname); 891d4afb5ceSopenharmony_ci // lwsl_notice("%s: dns query returned %d\n", __func__, n); 892d4afb5ceSopenharmony_ci if (n == LADNS_RET_FAILED) { 893d4afb5ceSopenharmony_ci lwsl_err("%s: async dns failed\n", __func__); 894d4afb5ceSopenharmony_ci wsi = NULL; 895d4afb5ceSopenharmony_ci /* 896d4afb5ceSopenharmony_ci * It was already closed by calling callback with error 897d4afb5ceSopenharmony_ci * from lws_async_dns_query() 898d4afb5ceSopenharmony_ci */ 899d4afb5ceSopenharmony_ci goto bail; 900d4afb5ceSopenharmony_ci } 901d4afb5ceSopenharmony_ci } else { 902d4afb5ceSopenharmony_ci lwsl_debug("%s: udp adopt has no ads\n", __func__); 903d4afb5ceSopenharmony_ci wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname); 904d4afb5ceSopenharmony_ci } 905d4afb5ceSopenharmony_ci 906d4afb5ceSopenharmony_ci /* dns lookup is happening asynchronously */ 907d4afb5ceSopenharmony_ci 908d4afb5ceSopenharmony_ci // lwsl_notice("%s: returning wsi %p\n", __func__, wsi); 909d4afb5ceSopenharmony_ci 910d4afb5ceSopenharmony_ci return wsi; 911d4afb5ceSopenharmony_ci#endif 912d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_SYS_ASYNC_DNS) 913d4afb5ceSopenharmony_cibail1: 914d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail"); 915d4afb5ceSopenharmony_ci wsi = NULL; 916d4afb5ceSopenharmony_ci#endif 917d4afb5ceSopenharmony_cibail: 918d4afb5ceSopenharmony_ci return wsi; 919d4afb5ceSopenharmony_ci#else 920d4afb5ceSopenharmony_ci return NULL; 921d4afb5ceSopenharmony_ci#endif 922d4afb5ceSopenharmony_ci} 923d4afb5ceSopenharmony_ci#endif 924d4afb5ceSopenharmony_ci#endif 925d4afb5ceSopenharmony_ci 926d4afb5ceSopenharmony_cistruct lws * 927d4afb5ceSopenharmony_cilws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd, 928d4afb5ceSopenharmony_ci const char *readbuf, size_t len) 929d4afb5ceSopenharmony_ci{ 930d4afb5ceSopenharmony_ci return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd), 931d4afb5ceSopenharmony_ci readbuf, len); 932d4afb5ceSopenharmony_ci} 933d4afb5ceSopenharmony_ci 934d4afb5ceSopenharmony_cistruct lws * 935d4afb5ceSopenharmony_cilws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost, 936d4afb5ceSopenharmony_ci lws_sockfd_type accept_fd, 937d4afb5ceSopenharmony_ci const char *readbuf, size_t len) 938d4afb5ceSopenharmony_ci{ 939d4afb5ceSopenharmony_ci return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd), 940d4afb5ceSopenharmony_ci readbuf, len); 941d4afb5ceSopenharmony_ci} 942