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