• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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