1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26
27 static 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
38 struct lws *
lws_http_client_connect_via_info2(struct lws * wsi)39 lws_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
70 no_ah:
71 return lws_client_connect_2_dnsreq(wsi);
72
73 bail:
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
84 int
lws_client_stash_create(struct lws * wsi,const char ** cisin)85 lws_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
127 struct lws *
lws_client_connect_via_info(const struct lws_client_connect_info * i)128 lws_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)
529 bail3:
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
539 bail:
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)
549 bail2:
550 #endif
551
552 if (i->pwsi)
553 *i->pwsi = NULL;
554
555 return NULL;
556 }
557