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_cistatic const uint8_t hnames[] = { 28d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_PEER_ADDRESS, 29d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_URI, 30d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_HOST, 31d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_ORIGIN, 32d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, 33d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_METHOD, 34d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_IFACE, 35d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_ALPN 36d4afb5ceSopenharmony_ci}; 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_cistruct lws * 39d4afb5ceSopenharmony_cilws_http_client_connect_via_info2(struct lws *wsi) 40d4afb5ceSopenharmony_ci{ 41d4afb5ceSopenharmony_ci struct client_info_stash *stash = wsi->stash; 42d4afb5ceSopenharmony_ci int n; 43d4afb5ceSopenharmony_ci 44d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "stash %p", stash); 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci if (!stash) 47d4afb5ceSopenharmony_ci return wsi; 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci wsi->a.opaque_user_data = wsi->stash->opaque_user_data; 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci if (stash->cis[CIS_METHOD] && (!strcmp(stash->cis[CIS_METHOD], "RAW") || 52d4afb5ceSopenharmony_ci !strcmp(stash->cis[CIS_METHOD], "MQTT"))) 53d4afb5ceSopenharmony_ci goto no_ah; 54d4afb5ceSopenharmony_ci 55d4afb5ceSopenharmony_ci /* 56d4afb5ceSopenharmony_ci * we're not necessarily in a position to action these right away, 57d4afb5ceSopenharmony_ci * stash them... we only need during connect phase so into a temp 58d4afb5ceSopenharmony_ci * allocated stash 59d4afb5ceSopenharmony_ci */ 60d4afb5ceSopenharmony_ci for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames); n++) 61d4afb5ceSopenharmony_ci if (hnames[n] && stash->cis[n] && 62d4afb5ceSopenharmony_ci lws_hdr_simple_create(wsi, hnames[n], stash->cis[n])) 63d4afb5ceSopenharmony_ci goto bail; 64d4afb5ceSopenharmony_ci 65d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SOCKS5) 66d4afb5ceSopenharmony_ci if (!wsi->a.vhost->socks_proxy_port) 67d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->stash); 68d4afb5ceSopenharmony_ci#endif 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_cino_ah: 71d4afb5ceSopenharmony_ci return lws_client_connect_2_dnsreq(wsi); 72d4afb5ceSopenharmony_ci 73d4afb5ceSopenharmony_cibail: 74d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SOCKS5) 75d4afb5ceSopenharmony_ci if (!wsi->a.vhost->socks_proxy_port) 76d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->stash); 77d4afb5ceSopenharmony_ci#endif 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->stash); 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci return NULL; 82d4afb5ceSopenharmony_ci} 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ciint 85d4afb5ceSopenharmony_cilws_client_stash_create(struct lws *wsi, const char **cisin) 86d4afb5ceSopenharmony_ci{ 87d4afb5ceSopenharmony_ci size_t size; 88d4afb5ceSopenharmony_ci char *pc; 89d4afb5ceSopenharmony_ci int n; 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci size = sizeof(*wsi->stash) + 1; 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci /* 94d4afb5ceSopenharmony_ci * Let's overallocate the stash object with space for all the args 95d4afb5ceSopenharmony_ci * in one hit. 96d4afb5ceSopenharmony_ci */ 97d4afb5ceSopenharmony_ci for (n = 0; n < CIS_COUNT; n++) 98d4afb5ceSopenharmony_ci if (cisin[n]) 99d4afb5ceSopenharmony_ci size += strlen(cisin[n]) + 1; 100d4afb5ceSopenharmony_ci 101d4afb5ceSopenharmony_ci if (wsi->stash) 102d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->stash); 103d4afb5ceSopenharmony_ci 104d4afb5ceSopenharmony_ci wsi->stash = lws_malloc(size, "client stash"); 105d4afb5ceSopenharmony_ci if (!wsi->stash) 106d4afb5ceSopenharmony_ci return 1; 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_ci /* all the pointers default to NULL, but no need to zero the args */ 109d4afb5ceSopenharmony_ci memset(wsi->stash, 0, sizeof(*wsi->stash)); 110d4afb5ceSopenharmony_ci 111d4afb5ceSopenharmony_ci pc = (char *)&wsi->stash[1]; 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci for (n = 0; n < CIS_COUNT; n++) 114d4afb5ceSopenharmony_ci if (cisin[n]) { 115d4afb5ceSopenharmony_ci size_t mm; 116d4afb5ceSopenharmony_ci wsi->stash->cis[n] = pc; 117d4afb5ceSopenharmony_ci if (n == CIS_PATH && cisin[n][0] != '/') 118d4afb5ceSopenharmony_ci *pc++ = '/'; 119d4afb5ceSopenharmony_ci mm = strlen(cisin[n]) + 1; 120d4afb5ceSopenharmony_ci memcpy(pc, cisin[n], mm); 121d4afb5ceSopenharmony_ci pc += mm; 122d4afb5ceSopenharmony_ci } 123d4afb5ceSopenharmony_ci 124d4afb5ceSopenharmony_ci return 0; 125d4afb5ceSopenharmony_ci} 126d4afb5ceSopenharmony_ci 127d4afb5ceSopenharmony_cistruct lws * 128d4afb5ceSopenharmony_cilws_client_connect_via_info(const struct lws_client_connect_info *i) 129d4afb5ceSopenharmony_ci{ 130d4afb5ceSopenharmony_ci const char *local = i->protocol; 131d4afb5ceSopenharmony_ci struct lws *wsi, *safe = NULL; 132d4afb5ceSopenharmony_ci const struct lws_protocols *p; 133d4afb5ceSopenharmony_ci const char *cisin[CIS_COUNT]; 134d4afb5ceSopenharmony_ci struct lws_vhost *vh; 135d4afb5ceSopenharmony_ci int tsi; 136d4afb5ceSopenharmony_ci 137d4afb5ceSopenharmony_ci if (i->context->requested_stop_internal_loops) 138d4afb5ceSopenharmony_ci return NULL; 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci if (!i->context->protocol_init_done) 141d4afb5ceSopenharmony_ci if (lws_protocol_init(i->context)) 142d4afb5ceSopenharmony_ci return NULL; 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci /* 145d4afb5ceSopenharmony_ci * If we have .local_protocol_name, use it to select the local protocol 146d4afb5ceSopenharmony_ci * handler to bind to. Otherwise use .protocol if http[s]. 147d4afb5ceSopenharmony_ci */ 148d4afb5ceSopenharmony_ci if (i->local_protocol_name) 149d4afb5ceSopenharmony_ci local = i->local_protocol_name; 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_ci lws_context_lock(i->context, __func__); 152d4afb5ceSopenharmony_ci /* 153d4afb5ceSopenharmony_ci * PHASE 1: if SMP, find out the tsi related to current service thread 154d4afb5ceSopenharmony_ci */ 155d4afb5ceSopenharmony_ci 156d4afb5ceSopenharmony_ci tsi = lws_pthread_self_to_tsi(i->context); 157d4afb5ceSopenharmony_ci assert(tsi >= 0); 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci /* PHASE 2: create a bare wsi */ 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_ci wsi = __lws_wsi_create_with_role(i->context, tsi, NULL, i->log_cx); 162d4afb5ceSopenharmony_ci lws_context_unlock(i->context); 163d4afb5ceSopenharmony_ci if (wsi == NULL) 164d4afb5ceSopenharmony_ci return NULL; 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci vh = i->vhost; 167d4afb5ceSopenharmony_ci if (!vh) { 168d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST) 169d4afb5ceSopenharmony_ci if (lws_tls_jit_trust_vhost_bind(i->context, i->address, &vh)) 170d4afb5ceSopenharmony_ci#endif 171d4afb5ceSopenharmony_ci { 172d4afb5ceSopenharmony_ci vh = lws_get_vhost_by_name(i->context, "default"); 173d4afb5ceSopenharmony_ci if (!vh) { 174d4afb5ceSopenharmony_ci 175d4afb5ceSopenharmony_ci vh = i->context->vhost_list; 176d4afb5ceSopenharmony_ci 177d4afb5ceSopenharmony_ci if (!vh) { /* coverity */ 178d4afb5ceSopenharmony_ci lwsl_cx_err(i->context, "no vhost"); 179d4afb5ceSopenharmony_ci goto bail; 180d4afb5ceSopenharmony_ci } 181d4afb5ceSopenharmony_ci if (!strcmp(vh->name, "system")) 182d4afb5ceSopenharmony_ci vh = vh->vhost_next; 183d4afb5ceSopenharmony_ci } 184d4afb5ceSopenharmony_ci } 185d4afb5ceSopenharmony_ci } 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS) 188d4afb5ceSopenharmony_ci /* any of these imply we are a client wsi bound to an SS, which 189d4afb5ceSopenharmony_ci * implies our opaque user ptr is the ss (or sspc if PROXY_LINK) handle 190d4afb5ceSopenharmony_ci */ 191d4afb5ceSopenharmony_ci wsi->for_ss = !!(i->ssl_connection & (LCCSCF_SECSTREAM_CLIENT | LCCSCF_SECSTREAM_PROXY_LINK | LCCSCF_SECSTREAM_PROXY_ONWARD)); 192d4afb5ceSopenharmony_ci wsi->client_bound_sspc = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK); /* so wsi close understands need to remove sspc ptr to wsi */ 193d4afb5ceSopenharmony_ci wsi->client_proxy_onward = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD); 194d4afb5ceSopenharmony_ci#endif 195d4afb5ceSopenharmony_ci 196d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION) 197d4afb5ceSopenharmony_ci wsi->fic.name = "wsi"; 198d4afb5ceSopenharmony_ci if (i->fic.fi_owner.count) 199d4afb5ceSopenharmony_ci /* 200d4afb5ceSopenharmony_ci * This moves all the lws_fi_t from i->fi to the vhost fi, 201d4afb5ceSopenharmony_ci * leaving it empty 202d4afb5ceSopenharmony_ci */ 203d4afb5ceSopenharmony_ci lws_fi_import(&wsi->fic, &i->fic); 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci lws_fi_inherit_copy(&wsi->fic, &i->context->fic, "wsi", i->fi_wsi_name); 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_ci if (lws_fi(&wsi->fic, "createfail")) 208d4afb5ceSopenharmony_ci goto bail; 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS) 211d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) 212d4afb5ceSopenharmony_ci if (wsi->client_bound_sspc) { 213d4afb5ceSopenharmony_ci lws_sspc_handle_t *fih = (lws_sspc_handle_t *)i->opaque_user_data; 214d4afb5ceSopenharmony_ci lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL); 215d4afb5ceSopenharmony_ci } 216d4afb5ceSopenharmony_ci#endif 217d4afb5ceSopenharmony_ci if (wsi->for_ss) { 218d4afb5ceSopenharmony_ci lws_ss_handle_t *fih = (lws_ss_handle_t *)i->opaque_user_data; 219d4afb5ceSopenharmony_ci lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL); 220d4afb5ceSopenharmony_ci } 221d4afb5ceSopenharmony_ci#endif 222d4afb5ceSopenharmony_ci#endif 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci lws_wsi_fault_timedclose(wsi); 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci /* 227d4afb5ceSopenharmony_ci * Until we exit, we can report connection failure directly to the 228d4afb5ceSopenharmony_ci * caller without needing to call through to protocol CONNECTION_ERROR. 229d4afb5ceSopenharmony_ci */ 230d4afb5ceSopenharmony_ci wsi->client_suppress_CONNECTION_ERROR = 1; 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci if (i->keep_warm_secs) 233d4afb5ceSopenharmony_ci wsi->keep_warm_secs = i->keep_warm_secs; 234d4afb5ceSopenharmony_ci else 235d4afb5ceSopenharmony_ci wsi->keep_warm_secs = 5; 236d4afb5ceSopenharmony_ci 237d4afb5ceSopenharmony_ci wsi->seq = i->seq; 238d4afb5ceSopenharmony_ci wsi->flags = i->ssl_connection; 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_ci wsi->c_pri = i->priority; 241d4afb5ceSopenharmony_ci 242d4afb5ceSopenharmony_ci if (i->retry_and_idle_policy) 243d4afb5ceSopenharmony_ci wsi->retry_policy = i->retry_and_idle_policy; 244d4afb5ceSopenharmony_ci else 245d4afb5ceSopenharmony_ci wsi->retry_policy = &i->context->default_retry; 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci if (i->ssl_connection & LCCSCF_WAKE_SUSPEND__VALIDITY) 248d4afb5ceSopenharmony_ci wsi->conn_validity_wakesuspend = 1; 249d4afb5ceSopenharmony_ci 250d4afb5ceSopenharmony_ci lws_vhost_bind_wsi(vh, wsi); 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_FAULT_INJECTION) 253d4afb5ceSopenharmony_ci /* additionally inerit from vhost we bound to */ 254d4afb5ceSopenharmony_ci lws_fi_inherit_copy(&wsi->fic, &vh->fic, "wsi", i->fi_wsi_name); 255d4afb5ceSopenharmony_ci#endif 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_ci if (!wsi->a.vhost) { 258d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "No vhost in the context"); 259d4afb5ceSopenharmony_ci 260d4afb5ceSopenharmony_ci goto bail; 261d4afb5ceSopenharmony_ci } 262d4afb5ceSopenharmony_ci 263d4afb5ceSopenharmony_ci /* 264d4afb5ceSopenharmony_ci * PHASE 3: Choose an initial role for the wsi and do role-specific init 265d4afb5ceSopenharmony_ci * 266d4afb5ceSopenharmony_ci * Note the initial role may not reflect the final role, eg, 267d4afb5ceSopenharmony_ci * we may want ws, but first we have to go through h1 to get that 268d4afb5ceSopenharmony_ci */ 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci if (lws_role_call_client_bind(wsi, i) < 0) { 271d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "unable to bind to role"); 272d4afb5ceSopenharmony_ci 273d4afb5ceSopenharmony_ci goto bail; 274d4afb5ceSopenharmony_ci } 275d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "role binding to %s", wsi->role_ops->name); 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci /* 278d4afb5ceSopenharmony_ci * PHASE 4: fill up the wsi with stuff from the connect_info as far as 279d4afb5ceSopenharmony_ci * it can go. It's uncertain because not only is our connection 280d4afb5ceSopenharmony_ci * going to complete asynchronously, we might have bound to h1 and not 281d4afb5ceSopenharmony_ci * even be able to get ahold of an ah immediately. 282d4afb5ceSopenharmony_ci */ 283d4afb5ceSopenharmony_ci 284d4afb5ceSopenharmony_ci wsi->user_space = NULL; 285d4afb5ceSopenharmony_ci wsi->pending_timeout = NO_PENDING_TIMEOUT; 286d4afb5ceSopenharmony_ci wsi->position_in_fds_table = LWS_NO_FDS_POS; 287d4afb5ceSopenharmony_ci wsi->ocport = wsi->c_port = (uint16_t)(unsigned int)i->port; 288d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert = i->sys_tls_client_cert; 289d4afb5ceSopenharmony_ci 290d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 291d4afb5ceSopenharmony_ci wsi->txc.manual_initial_tx_credit = 292d4afb5ceSopenharmony_ci (int32_t)i->manual_initial_tx_credit; 293d4afb5ceSopenharmony_ci#endif 294d4afb5ceSopenharmony_ci 295d4afb5ceSopenharmony_ci wsi->a.protocol = &wsi->a.vhost->protocols[0]; 296d4afb5ceSopenharmony_ci wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE); 297d4afb5ceSopenharmony_ci wsi->client_no_follow_redirect = !!(i->ssl_connection & 298d4afb5ceSopenharmony_ci LCCSCF_HTTP_NO_FOLLOW_REDIRECT); 299d4afb5ceSopenharmony_ci 300d4afb5ceSopenharmony_ci /* 301d4afb5ceSopenharmony_ci * PHASE 5: handle external user_space now, generic alloc is done in 302d4afb5ceSopenharmony_ci * role finalization 303d4afb5ceSopenharmony_ci */ 304d4afb5ceSopenharmony_ci 305d4afb5ceSopenharmony_ci if (i->userdata) { 306d4afb5ceSopenharmony_ci wsi->user_space_externally_allocated = 1; 307d4afb5ceSopenharmony_ci wsi->user_space = i->userdata; 308d4afb5ceSopenharmony_ci } 309d4afb5ceSopenharmony_ci 310d4afb5ceSopenharmony_ci if (local) { 311d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "vh %s protocol binding to %s\n", 312d4afb5ceSopenharmony_ci wsi->a.vhost->name, local); 313d4afb5ceSopenharmony_ci p = lws_vhost_name_to_protocol(wsi->a.vhost, local); 314d4afb5ceSopenharmony_ci if (p) 315d4afb5ceSopenharmony_ci lws_bind_protocol(wsi, p, __func__); 316d4afb5ceSopenharmony_ci else 317d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "unknown protocol %s", local); 318d4afb5ceSopenharmony_ci 319d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "%s: %s %s entry", 320d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), wsi->role_ops->name, 321d4afb5ceSopenharmony_ci wsi->a.protocol ? wsi->a.protocol->name : "none"); 322d4afb5ceSopenharmony_ci } 323d4afb5ceSopenharmony_ci 324d4afb5ceSopenharmony_ci /* 325d4afb5ceSopenharmony_ci * PHASE 5: handle external user_space now, generic alloc is done in 326d4afb5ceSopenharmony_ci * role finalization 327d4afb5ceSopenharmony_ci */ 328d4afb5ceSopenharmony_ci 329d4afb5ceSopenharmony_ci if (!wsi->user_space && i->userdata) { 330d4afb5ceSopenharmony_ci wsi->user_space_externally_allocated = 1; 331d4afb5ceSopenharmony_ci wsi->user_space = i->userdata; 332d4afb5ceSopenharmony_ci } 333d4afb5ceSopenharmony_ci 334d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 335d4afb5ceSopenharmony_ci wsi->tls.use_ssl = (unsigned int)i->ssl_connection; 336d4afb5ceSopenharmony_ci#else 337d4afb5ceSopenharmony_ci if (i->ssl_connection & LCCSCF_USE_SSL) { 338d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "lws not configured for tls"); 339d4afb5ceSopenharmony_ci goto bail; 340d4afb5ceSopenharmony_ci } 341d4afb5ceSopenharmony_ci#endif 342d4afb5ceSopenharmony_ci 343d4afb5ceSopenharmony_ci /* 344d4afb5ceSopenharmony_ci * PHASE 6: stash the things from connect_info that we can't process 345d4afb5ceSopenharmony_ci * right now, eg, if http binding, without an ah. If h1 and no ah, we 346d4afb5ceSopenharmony_ci * will go on the ah waiting list and process those things later (after 347d4afb5ceSopenharmony_ci * the connect_info and maybe the things pointed to have gone out of 348d4afb5ceSopenharmony_ci * scope) 349d4afb5ceSopenharmony_ci * 350d4afb5ceSopenharmony_ci * However these things are stashed in a generic way at this point, 351d4afb5ceSopenharmony_ci * with no relationship to http or ah 352d4afb5ceSopenharmony_ci */ 353d4afb5ceSopenharmony_ci 354d4afb5ceSopenharmony_ci cisin[CIS_ADDRESS] = i->address; 355d4afb5ceSopenharmony_ci cisin[CIS_PATH] = i->path; 356d4afb5ceSopenharmony_ci cisin[CIS_HOST] = i->host; 357d4afb5ceSopenharmony_ci cisin[CIS_ORIGIN] = i->origin; 358d4afb5ceSopenharmony_ci cisin[CIS_PROTOCOL] = i->protocol; 359d4afb5ceSopenharmony_ci cisin[CIS_METHOD] = i->method; 360d4afb5ceSopenharmony_ci cisin[CIS_IFACE] = i->iface; 361d4afb5ceSopenharmony_ci cisin[CIS_ALPN] = i->alpn; 362d4afb5ceSopenharmony_ci 363d4afb5ceSopenharmony_ci if (lws_client_stash_create(wsi, cisin)) 364d4afb5ceSopenharmony_ci goto bail; 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 367d4afb5ceSopenharmony_ci if (i->alpn) 368d4afb5ceSopenharmony_ci lws_strncpy(wsi->alpn, i->alpn, sizeof(wsi->alpn)); 369d4afb5ceSopenharmony_ci#endif 370d4afb5ceSopenharmony_ci 371d4afb5ceSopenharmony_ci wsi->a.opaque_user_data = wsi->stash->opaque_user_data = 372d4afb5ceSopenharmony_ci i->opaque_user_data; 373d4afb5ceSopenharmony_ci 374d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS) 375d4afb5ceSopenharmony_ci 376d4afb5ceSopenharmony_ci if (wsi->for_ss) { 377d4afb5ceSopenharmony_ci /* it's related to ss... the options are 378d4afb5ceSopenharmony_ci * 379d4afb5ceSopenharmony_ci * LCCSCF_SECSTREAM_PROXY_LINK : client SSPC link to proxy 380d4afb5ceSopenharmony_ci * LCCSCF_SECSTREAM_PROXY_ONWARD: proxy's onward connection 381d4afb5ceSopenharmony_ci */ 382d4afb5ceSopenharmony_ci __lws_lc_tag(i->context, &i->context->lcg[ 383d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) 384d4afb5ceSopenharmony_ci i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK ? LWSLCG_WSI_SSP_CLIENT : 385d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 386d4afb5ceSopenharmony_ci (i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD ? LWSLCG_WSI_SSP_ONWARD : 387d4afb5ceSopenharmony_ci#endif 388d4afb5ceSopenharmony_ci LWSLCG_WSI_CLIENT 389d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 390d4afb5ceSopenharmony_ci ) 391d4afb5ceSopenharmony_ci#endif 392d4afb5ceSopenharmony_ci ], 393d4afb5ceSopenharmony_ci#else 394d4afb5ceSopenharmony_ci LWSLCG_WSI_CLIENT], 395d4afb5ceSopenharmony_ci#endif 396d4afb5ceSopenharmony_ci &wsi->lc, "%s/%s/%s/(%s)", i->method ? i->method : "WS", 397d4afb5ceSopenharmony_ci wsi->role_ops->name, i->address, 398d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) 399d4afb5ceSopenharmony_ci wsi->client_bound_sspc ? 400d4afb5ceSopenharmony_ci lws_sspc_tag((lws_sspc_handle_t *)i->opaque_user_data) : 401d4afb5ceSopenharmony_ci#endif 402d4afb5ceSopenharmony_ci lws_ss_tag(((lws_ss_handle_t *)i->opaque_user_data))); 403d4afb5ceSopenharmony_ci } else 404d4afb5ceSopenharmony_ci#endif 405d4afb5ceSopenharmony_ci __lws_lc_tag(i->context, &i->context->lcg[LWSLCG_WSI_CLIENT], &wsi->lc, 406d4afb5ceSopenharmony_ci "%s/%s/%s/%s", i->method ? i->method : "WS", 407d4afb5ceSopenharmony_ci wsi->role_ops->name ? wsi->role_ops->name : "novh", vh->name, i->address); 408d4afb5ceSopenharmony_ci 409d4afb5ceSopenharmony_ci lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name); 410d4afb5ceSopenharmony_ci 411d4afb5ceSopenharmony_ci /* 412d4afb5ceSopenharmony_ci * at this point user callbacks like 413d4afb5ceSopenharmony_ci * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to 414d4afb5ceSopenharmony_ci * know the parent... eg for proxying we can grab extra headers from 415d4afb5ceSopenharmony_ci * the parent's incoming ah and add them to the child client handshake 416d4afb5ceSopenharmony_ci */ 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ci if (i->parent_wsi) { 419d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "created as child %s", 420d4afb5ceSopenharmony_ci lws_wsi_tag(i->parent_wsi)); 421d4afb5ceSopenharmony_ci wsi->parent = i->parent_wsi; 422d4afb5ceSopenharmony_ci safe = wsi->sibling_list = i->parent_wsi->child_list; 423d4afb5ceSopenharmony_ci i->parent_wsi->child_list = wsi; 424d4afb5ceSopenharmony_ci } 425d4afb5ceSopenharmony_ci 426d4afb5ceSopenharmony_ci /* 427d4afb5ceSopenharmony_ci * PHASE 7: Do any role-specific finalization processing. We can still 428d4afb5ceSopenharmony_ci * see important info things via wsi->stash 429d4afb5ceSopenharmony_ci */ 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_client_bind)) { 432d4afb5ceSopenharmony_ci 433d4afb5ceSopenharmony_ci int n = lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_client_bind). 434d4afb5ceSopenharmony_ci client_bind(wsi, NULL); 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci if (n && i->parent_wsi) 437d4afb5ceSopenharmony_ci /* unpick from parent */ 438d4afb5ceSopenharmony_ci i->parent_wsi->child_list = safe; 439d4afb5ceSopenharmony_ci 440d4afb5ceSopenharmony_ci if (n < 0) 441d4afb5ceSopenharmony_ci /* we didn't survive, wsi is freed */ 442d4afb5ceSopenharmony_ci goto bail2; 443d4afb5ceSopenharmony_ci 444d4afb5ceSopenharmony_ci if (n) 445d4afb5ceSopenharmony_ci /* something else failed, wsi needs freeing */ 446d4afb5ceSopenharmony_ci goto bail; 447d4afb5ceSopenharmony_ci } 448d4afb5ceSopenharmony_ci 449d4afb5ceSopenharmony_ci /* let the caller's optional wsi storage have the wsi we created */ 450d4afb5ceSopenharmony_ci 451d4afb5ceSopenharmony_ci if (i->pwsi) 452d4afb5ceSopenharmony_ci *i->pwsi = wsi; 453d4afb5ceSopenharmony_ci 454d4afb5ceSopenharmony_ci if (!wsi->a.protocol) 455d4afb5ceSopenharmony_ci /* we must have one protocol or another bound by this point */ 456d4afb5ceSopenharmony_ci goto bail; 457d4afb5ceSopenharmony_ci 458d4afb5ceSopenharmony_ci /* PHASE 8: notify protocol with role-specific connected callback */ 459d4afb5ceSopenharmony_ci 460d4afb5ceSopenharmony_ci /* raw socket per se doesn't want this... raw socket proxy wants it... */ 461d4afb5ceSopenharmony_ci 462d4afb5ceSopenharmony_ci if (wsi->role_ops != &role_ops_raw_skt || 463d4afb5ceSopenharmony_ci (i->local_protocol_name && 464d4afb5ceSopenharmony_ci !strcmp(i->local_protocol_name, "raw-proxy"))) { 465d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "adoption cb %d to %s %s", 466d4afb5ceSopenharmony_ci wsi->role_ops->adoption_cb[0], 467d4afb5ceSopenharmony_ci wsi->role_ops->name, wsi->a.protocol->name); 468d4afb5ceSopenharmony_ci 469d4afb5ceSopenharmony_ci wsi->a.protocol->callback(wsi, wsi->role_ops->adoption_cb[0], 470d4afb5ceSopenharmony_ci wsi->user_space, NULL, 0); 471d4afb5ceSopenharmony_ci } 472d4afb5ceSopenharmony_ci 473d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HUBBUB) 474d4afb5ceSopenharmony_ci if (i->uri_replace_to) 475d4afb5ceSopenharmony_ci wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb, 476d4afb5ceSopenharmony_ci i->uri_replace_from, 477d4afb5ceSopenharmony_ci i->uri_replace_to); 478d4afb5ceSopenharmony_ci#endif 479d4afb5ceSopenharmony_ci 480d4afb5ceSopenharmony_ci if (i->method && (!strcmp(i->method, "RAW") // || 481d4afb5ceSopenharmony_ci// !strcmp(i->method, "MQTT") 482d4afb5ceSopenharmony_ci )) { 483d4afb5ceSopenharmony_ci 484d4afb5ceSopenharmony_ci /* 485d4afb5ceSopenharmony_ci * Not for MQTT here, since we don't know if we will 486d4afb5ceSopenharmony_ci * pipeline it or not... 487d4afb5ceSopenharmony_ci */ 488d4afb5ceSopenharmony_ci 489d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci wsi->tls.ssl = NULL; 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci if (wsi->tls.use_ssl & LCCSCF_USE_SSL) { 494d4afb5ceSopenharmony_ci const char *cce = NULL; 495d4afb5ceSopenharmony_ci 496d4afb5ceSopenharmony_ci switch ( 497d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_SYS_ASYNC_DNS) 498d4afb5ceSopenharmony_ci lws_client_create_tls(wsi, &cce, 1) 499d4afb5ceSopenharmony_ci#else 500d4afb5ceSopenharmony_ci lws_client_create_tls(wsi, &cce, 0) 501d4afb5ceSopenharmony_ci#endif 502d4afb5ceSopenharmony_ci ) { 503d4afb5ceSopenharmony_ci case 1: 504d4afb5ceSopenharmony_ci return wsi; 505d4afb5ceSopenharmony_ci case 0: 506d4afb5ceSopenharmony_ci break; 507d4afb5ceSopenharmony_ci default: 508d4afb5ceSopenharmony_ci goto bail3; 509d4afb5ceSopenharmony_ci } 510d4afb5ceSopenharmony_ci } 511d4afb5ceSopenharmony_ci#endif 512d4afb5ceSopenharmony_ci 513d4afb5ceSopenharmony_ci 514d4afb5ceSopenharmony_ci /* fallthru */ 515d4afb5ceSopenharmony_ci 516d4afb5ceSopenharmony_ci wsi = lws_http_client_connect_via_info2(wsi); 517d4afb5ceSopenharmony_ci } 518d4afb5ceSopenharmony_ci 519d4afb5ceSopenharmony_ci if (wsi) 520d4afb5ceSopenharmony_ci /* 521d4afb5ceSopenharmony_ci * If it subsequently fails, report CONNECTION_ERROR, 522d4afb5ceSopenharmony_ci * because we're going to return a non-error return now. 523d4afb5ceSopenharmony_ci */ 524d4afb5ceSopenharmony_ci wsi->client_suppress_CONNECTION_ERROR = 0; 525d4afb5ceSopenharmony_ci 526d4afb5ceSopenharmony_ci return wsi; 527d4afb5ceSopenharmony_ci 528d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 529d4afb5ceSopenharmony_cibail3: 530d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "tls start fail"); 531d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "tls start fail"); 532d4afb5ceSopenharmony_ci 533d4afb5ceSopenharmony_ci if (i->pwsi) 534d4afb5ceSopenharmony_ci *i->pwsi = NULL; 535d4afb5ceSopenharmony_ci 536d4afb5ceSopenharmony_ci return NULL; 537d4afb5ceSopenharmony_ci#endif 538d4afb5ceSopenharmony_ci 539d4afb5ceSopenharmony_cibail: 540d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS) 541d4afb5ceSopenharmony_ci if (wsi->tls.ssl) 542d4afb5ceSopenharmony_ci lws_tls_restrict_return(wsi); 543d4afb5ceSopenharmony_ci#endif 544d4afb5ceSopenharmony_ci 545d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->stash); 546d4afb5ceSopenharmony_ci lws_fi_destroy(&wsi->fic); 547d4afb5ceSopenharmony_ci lws_free(wsi); 548d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 549d4afb5ceSopenharmony_cibail2: 550d4afb5ceSopenharmony_ci#endif 551d4afb5ceSopenharmony_ci 552d4afb5ceSopenharmony_ci if (i->pwsi) 553d4afb5ceSopenharmony_ci *i->pwsi = NULL; 554d4afb5ceSopenharmony_ci 555d4afb5ceSopenharmony_ci return NULL; 556d4afb5ceSopenharmony_ci} 557