• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 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 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
28 static int
lws_getaddrinfo46(struct lws * wsi,const char * ads,struct addrinfo ** result)29 lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
30 {
31 	struct addrinfo hints;
32 	int n;
33 
34 	memset(&hints, 0, sizeof(hints));
35 	*result = NULL;
36 
37 	hints.ai_socktype = SOCK_STREAM;
38 
39 #ifdef LWS_WITH_IPV6
40 	if (wsi->ipv6) {
41 
42 #if !defined(__ANDROID__)
43 		hints.ai_family = AF_UNSPEC;
44 		hints.ai_flags = AI_V4MAPPED;
45 #endif
46 	} else
47 #endif
48 	{
49 		hints.ai_family = PF_UNSPEC;
50 	}
51 
52 	n = getaddrinfo(ads, NULL, &hints, result);
53 
54 	lwsl_info("%s: getaddrinfo '%s' says %d\n", __func__, ads, n);
55 
56 	return n;
57 }
58 #endif
59 
60 struct lws *
lws_client_connect_4_established(struct lws * wsi,struct lws * wsi_piggyback,ssize_t plen)61 lws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback,
62 				 ssize_t plen)
63 {
64 #if defined(LWS_CLIENT_HTTP_PROXYING)
65 	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
66 #endif
67 	const char *meth;
68 	struct lws_pollfd pfd;
69 	const char *cce = "";
70 	int n, m, rawish = 0;
71 
72 	meth = lws_wsi_client_stash_item(wsi, CIS_METHOD,
73 					 _WSI_TOKEN_CLIENT_METHOD);
74 
75 	if (meth && (!strcmp(meth, "RAW")
76 #if defined(LWS_ROLE_MQTT)
77 		     || !strcmp(meth, "MQTT")
78 #endif
79 	))
80 		rawish = 1;
81 
82 	if (wsi_piggyback)
83 		goto send_hs;
84 
85 #if defined(LWS_CLIENT_HTTP_PROXYING)
86 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
87 	/* we are connected to server, or proxy */
88 
89 	/* http proxy */
90 	if (wsi->vhost->http.http_proxy_port) {
91 		const char *cpa;
92 
93 		cpa = lws_wsi_client_stash_item(wsi, CIS_ADDRESS,
94 						_WSI_TOKEN_CLIENT_PEER_ADDRESS);
95 		if (!cpa)
96 			goto failed;
97 
98 		lwsl_info("%s: going via proxy\n", __func__);
99 
100 		plen = lws_snprintf((char *)pt->serv_buf, 256,
101 			"CONNECT %s:%u HTTP/1.1\x0d\x0a"
102 			"Host: %s:%u\x0d\x0a"
103 			"User-agent: lws\x0d\x0a", cpa, wsi->ocport,
104 						   cpa, wsi->ocport);
105 
106 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
107 		if (wsi->vhost->proxy_basic_auth_token[0])
108 			plen += lws_snprintf((char *)pt->serv_buf + plen, 256,
109 					"Proxy-authorization: basic %s\x0d\x0a",
110 					wsi->vhost->proxy_basic_auth_token);
111 #endif
112 
113 		plen += lws_snprintf((char *)pt->serv_buf + plen, 5, "\x0d\x0a");
114 
115 		/* lwsl_hexdump_notice(pt->serv_buf, plen); */
116 
117 		/*
118 		 * OK from now on we talk via the proxy, so connect to that
119 		 */
120 		if (wsi->stash)
121 			wsi->stash->cis[CIS_ADDRESS] =
122 				wsi->vhost->http.http_proxy_address;
123 		else
124 			if (lws_hdr_simple_create(wsi,
125 					_WSI_TOKEN_CLIENT_PEER_ADDRESS,
126 					  wsi->vhost->http.http_proxy_address))
127 			goto failed;
128 		wsi->c_port = wsi->vhost->http.http_proxy_port;
129 
130 		n = send(wsi->desc.sockfd, (char *)pt->serv_buf, (int)plen,
131 			 MSG_NOSIGNAL);
132 		if (n < 0) {
133 			lwsl_debug("ERROR writing to proxy socket\n");
134 			cce = "proxy write failed";
135 			goto failed;
136 		}
137 
138 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
139 				wsi->context->timeout_secs);
140 
141 		lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
142 
143 		return wsi;
144 	}
145 #endif
146 #endif
147 
148 #if defined(LWS_WITH_SOCKS5)
149 	if (lwsi_state(wsi) != 	LRS_ESTABLISHED)
150 		switch (lws_socks5c_greet(wsi, &cce)) {
151 		case -1:
152 			goto failed;
153 		case 1:
154 			return wsi;
155 		default:
156 			break;
157 		}
158 #endif
159 
160 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
161 send_hs:
162 
163 	if (wsi_piggyback &&
164 	    !lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
165 		/*
166 		 * We are pipelining on an already-established connection...
167 		 * we can skip tls establishment.
168 		 *
169 		 * Set these queued guys to a state where they won't actually
170 		 * send their headers until we decide later.
171 		 */
172 
173 		lwsi_set_state(wsi, LRS_H2_WAITING_TO_SEND_HEADERS);
174 
175 		/*
176 		 * we can't send our headers directly, because they have to
177 		 * be sent when the parent is writeable.  The parent will check
178 		 * for anybody on his client transaction queue that is in
179 		 * LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
180 		 *
181 		 * If we are trying to do this too early, before the master
182 		 * connection has written his own headers, then it will just
183 		 * wait in the queue until it's possible to send them.
184 		 */
185 		lws_callback_on_writable(wsi_piggyback);
186 #if defined(LWS_WITH_DETAILED_LATENCY)
187 		wsi->detlat.earliest_write_req =
188 			wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
189 #endif
190 		lwsl_info("%s: wsi %p: waiting to send hdrs (par state 0x%x)\n",
191 			    __func__, wsi, lwsi_state(wsi_piggyback));
192 	} else {
193 		lwsl_info("%s: wsi %p: %s %s client created own conn (raw %d) vh %sm st 0x%x\n",
194 			    __func__, wsi, wsi->role_ops->name,
195 			    wsi->protocol->name, rawish, wsi->vhost->name, lwsi_state(wsi));
196 
197 		/* we are making our own connection */
198 
199 #if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
200 
201 		/* we have connected if we got here */
202 
203 		if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
204 		    (wsi->tls.use_ssl & LCCSCF_USE_SSL)) {
205 
206 
207 
208 			/* we can retry this... just cook the SSL BIO the first time */
209 
210 			switch (lws_client_create_tls(wsi, &cce, 1)) {
211 			case 0:
212 				break;
213 			case 1:
214 				return wsi;
215 			default:
216 				goto failed;
217 			}
218 
219 
220 
221 			lwsl_notice("%s: wsi %p: st 0x%x\n",
222 				    __func__, wsi, lwsi_state(wsi));
223 
224 			if (lwsi_state(wsi) == LRS_WAITING_CONNECT)
225 				lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
226 			lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
227 					wsi->context->timeout_secs);
228 
229 			//if ()
230 			return wsi;
231 		}
232 #endif
233 
234 		if (!rawish)
235 			lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
236 		else {
237 			/* for a method = "RAW" connection, this makes us
238 			 * established */
239 
240 
241 			/* clear his established timeout */
242 			lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
243 
244 			m = wsi->role_ops->adoption_cb[0];
245 			if (m) {
246 				n = user_callback_handle_rxflow(
247 						wsi->protocol->callback, wsi,
248 						m, wsi->user_space, NULL, 0);
249 				if (n < 0) {
250 					lwsl_info("LWS_CALLBACK_RAW_PROXY_CLI_ADOPT failed\n");
251 					goto failed;
252 				}
253 			}
254 
255 			/* service.c pollout processing wants this */
256 			wsi->hdr_parsing_completed = 1;
257 #if defined(LWS_ROLE_MQTT)
258 			if (!strcmp(meth, "MQTT")) {
259 #if defined(LWS_WITH_TLS)
260 				if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
261 					lwsi_set_state(wsi, LRS_WAITING_SSL);
262 					return wsi;
263 				}
264 #endif
265 				lwsl_info("%s: settings LRS_MQTTC_IDLE\n",
266 					  __func__);
267 				lwsi_set_state(wsi, LRS_MQTTC_IDLE);
268 
269 				/*
270 				 * provoke service to issue the CONNECT directly.
271 				 */
272 				lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
273 						AWAITING_TIMEOUT);
274 
275 				assert(lws_socket_is_valid(wsi->desc.sockfd));
276 
277 				pfd.fd = wsi->desc.sockfd;
278 				pfd.events = LWS_POLLIN;
279 				pfd.revents = LWS_POLLOUT;
280 
281 				lwsl_info("%s: going to service fd\n", __func__);
282 				n = lws_service_fd(wsi->context, &pfd);
283 				if (n < 0) {
284 					cce = "first service failed";
285 					goto failed;
286 				}
287 				if (n) /* returns 1 on failure after closing wsi */
288 					return NULL;
289 				return wsi;
290 			}
291 #endif
292 			lwsl_info("%s: setting ESTABLISHED\n", __func__);
293 			lwsi_set_state(wsi, LRS_ESTABLISHED);
294 
295 			return wsi;
296 		}
297 
298 		/*
299 		 * provoke service to issue the handshake directly.
300 		 *
301 		 * we need to do it this way because in the proxy case, this is
302 		 * the next state and executed only if and when we get a good
303 		 * proxy response inside the state machine... but notice in
304 		 * SSL case this may not have sent anything yet with 0 return,
305 		 * and won't until many retries from main loop.  To stop that
306 		 * becoming endless, cover with a timeout.
307 		 */
308 
309 		lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
310 				wsi->context->timeout_secs);
311 
312 		assert(lws_socket_is_valid(wsi->desc.sockfd));
313 
314 		pfd.fd = wsi->desc.sockfd;
315 		pfd.events = LWS_POLLIN;
316 		pfd.revents = LWS_POLLIN;
317 
318 		n = lws_service_fd(wsi->context, &pfd);
319 		if (n < 0) {
320 			cce = "first service failed";
321 			goto failed;
322 		}
323 		if (n) /* returns 1 on failure after closing wsi */
324 			return NULL;
325 	}
326 #endif
327 	return wsi;
328 
329 failed:
330 	lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
331 
332 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
333 
334 	return NULL;
335 }
336 
337 struct lws *
lws_client_connect_3_connect(struct lws * wsi,const char * ads,const struct addrinfo * result,int n,void * opaque)338 lws_client_connect_3_connect(struct lws *wsi, const char *ads,
339 			     const struct addrinfo *result, int n, void *opaque)
340 {
341 #if defined(LWS_WITH_UNIX_SOCK)
342 	struct sockaddr_un sau;
343 #endif
344 #ifdef LWS_WITH_IPV6
345 	char ipv6only = lws_check_opt(wsi->vhost->options,
346 				      LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
347 				      LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
348 #endif
349 	const struct sockaddr *psa = NULL;
350 	const char *cce = "", *iface;
351 	uint16_t port = wsi->c_port;
352 	lws_sockaddr46 sa46;
353 	ssize_t plen = 0;
354 	char ni[48];
355 	int m;
356 
357 #if defined(LWS_WITH_IPV6) && defined(__ANDROID__)
358 	ipv6only = 0;
359 #endif
360 
361 	/*
362 	 * async dns calls back here for everybody who cares when it gets a
363 	 * result... but if we are piggybacking, we do not want to connect
364 	 * ourselves
365 	 */
366 
367 	if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue))
368 		return wsi;
369 #if 0
370 	if (!ads && !result) {
371 		cce = "dns resolution failed";
372 		if (!wsi->oom4)
373 			goto oom4;
374 		else
375 			goto failed;
376 	}
377 #endif
378 #if !defined(WIN32)
379 	/*
380 	* We can check using getsockopt if our connect actually completed.
381 	* Posix connect() allows nonblocking to redo the connect to
382 	* find out if it succeeded, for win32 we have to use this path
383 	* and take WSAEALREADY as a successful connect.
384 	*/
385 
386 	if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
387 	    lws_socket_is_valid(wsi->desc.sockfd)) {
388 		socklen_t sl = sizeof(int);
389 		int e = 0;
390 
391 		/*
392 		* this resets SO_ERROR after reading it.  If there's an error
393 		* condition the connect definitively failed.
394 		*/
395 
396 		if (!getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR,
397 #if defined(WIN32)
398 				(char *)
399 #endif
400 				&e, &sl)) {
401 			if (!e) {
402 				lwsl_info("%s: getsockopt check: conn OK\n",
403 						__func__);
404 
405 				goto conn_good;
406 			}
407 
408 			lwsl_debug("%s: getsockopt fd %d says err %d\n", __func__,
409 					wsi->desc.sockfd, e);
410 		}
411 
412 		lwsl_debug("%s: getsockopt check: conn fail: errno %d\n",
413 				__func__, LWS_ERRNO);
414 		goto try_next_result_fds;
415 	}
416 #endif
417 
418 #if defined(LWS_WITH_UNIX_SOCK)
419 	if (ads && *ads == '+') {
420 		ads++;
421 		memset(&sa46, 0, sizeof(sa46));
422 		memset(&sau, 0, sizeof(sau));
423 		sau.sun_family = AF_UNIX;
424 		strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
425 		sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';
426 
427 		lwsl_info("%s: Unix skt: %s\n", __func__, ads);
428 
429 		if (sau.sun_path[0] == '@')
430 			sau.sun_path[0] = '\0';
431 
432 		goto ads_known;
433 	}
434 #endif
435 
436 #if defined(LWS_WITH_SYS_ASYNC_DNS)
437 	if (n == LADNS_RET_FAILED) {
438 		lwsl_notice("%s: adns failed %s\n", __func__, ads);
439 		goto oom4;
440 	}
441 #endif
442 
443 	if (!wsi->dns_results) {
444 		wsi->dns_results_next = wsi->dns_results = result;
445 		if (result)
446 			lwsl_debug("%s: result %p result->ai_next %p\n",
447 					__func__, result, result->ai_next);
448 	}
449 
450 #if defined(LWS_WITH_DETAILED_LATENCY)
451 	if (lwsi_state(wsi) == LRS_WAITING_DNS &&
452 	    wsi->context->detailed_latency_cb) {
453 		wsi->detlat.type = LDLT_NAME_RESOLUTION;
454 		wsi->detlat.latencies[LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE] =
455 			lws_now_usecs() -
456 			wsi->detlat.earliest_write_req_pre_write;
457 		wsi->detlat.latencies[LAT_DUR_USERCB] = 0;
458 		lws_det_lat_cb(wsi->context, &wsi->detlat);
459 		wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
460 	}
461 #endif
462 #if defined(LWS_CLIENT_HTTP_PROXYING) && \
463 	(defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
464 
465 	/* Decide what it is we need to connect to:
466 	 *
467 	 * Priority 1: connect to http proxy */
468 
469 	if (wsi->vhost->http.http_proxy_port) {
470 		ads = wsi->vhost->http.http_proxy_address;
471 		port = wsi->vhost->http.http_proxy_port;
472 #else
473 		if (0) {
474 #endif
475 
476 #if defined(LWS_WITH_SOCKS5)
477 
478 	/* Priority 2: Connect to SOCK5 Proxy */
479 
480 	} else if (wsi->vhost->socks_proxy_port) {
481 		if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_GREETING, &plen)) {
482 			cce = "socks msg too large";
483 			goto oom4;
484 		}
485 
486 		lwsl_client("Sending SOCKS Greeting\n");
487 		ads = wsi->vhost->socks_proxy_address;
488 		port = wsi->vhost->socks_proxy_port;
489 #endif
490 	}
491 
492 	memset(&sa46, 0, sizeof(sa46));
493 
494 	if (n || !wsi->dns_results) {
495 		/* lws_getaddrinfo46 failed, there is no usable result */
496 		lwsl_notice("%s: lws_getaddrinfo46 failed %d\n",
497 				__func__, n);
498 
499 		cce = "ipv6 lws_getaddrinfo46 failed";
500 		goto oom4;
501 	}
502 
503 	/*
504 	 * Let's try connecting to each of the results in turn until one works
505 	 * or we run out of results
506 	 */
507 
508 next_result:
509 
510 	psa = (const struct sockaddr *)&sa46;
511 	n = sizeof(sa46);
512 	memset(&sa46, 0, sizeof(sa46));
513 
514 	switch (wsi->dns_results_next->ai_family) {
515 	case AF_INET:
516 #if defined(LWS_WITH_IPV6)
517 		if (ipv6only) {
518 			sa46.sa4.sin_family = AF_INET6;
519 
520 			/* map IPv4 to IPv6 */
521 			memset((char *)&sa46.sa6.sin6_addr, 0,
522 						sizeof(sa46.sa6.sin6_addr));
523 			sa46.sa6.sin6_addr.s6_addr[10] = 0xff;
524 			sa46.sa6.sin6_addr.s6_addr[11] = 0xff;
525 			memcpy(&sa46.sa6.sin6_addr.s6_addr[12],
526 				&((struct sockaddr_in *)
527 				    wsi->dns_results_next->ai_addr)->sin_addr,
528 							sizeof(struct in_addr));
529 			sa46.sa6.sin6_port = htons(port);
530 			ni[0] = '\0';
531 			lws_write_numeric_address(sa46.sa6.sin6_addr.s6_addr,
532 						  16, ni, sizeof(ni));
533 			lwsl_info("%s: %s ipv4->ipv6 %s\n", __func__, ads, ni);
534 			break;
535 		}
536 #endif
537 		sa46.sa4.sin_family = AF_INET;
538 		sa46.sa4.sin_addr.s_addr =
539 			((struct sockaddr_in *)wsi->dns_results_next->ai_addr)->
540 								sin_addr.s_addr;
541 		memset(&sa46.sa4.sin_zero, 0, sizeof(sa46.sa4.sin_zero));
542 		sa46.sa4.sin_port = htons(port);
543 		n = sizeof(struct sockaddr_in);
544 		lws_write_numeric_address((uint8_t *)&sa46.sa4.sin_addr.s_addr,
545 					  4, ni, sizeof(ni));
546 		lwsl_info("%s: %s ipv4 %s\n", __func__, ads, ni);
547 		break;
548 	case AF_INET6:
549 #if defined(LWS_WITH_IPV6)
550 		if (!wsi->ipv6)
551 			goto try_next_result;
552 		sa46.sa4.sin_family = AF_INET6;
553 		memcpy(&sa46.sa6.sin6_addr,
554 		       &((struct sockaddr_in6 *)wsi->dns_results_next->ai_addr)->
555 				       sin6_addr, sizeof(struct in6_addr));
556 		sa46.sa6.sin6_scope_id = ((struct sockaddr_in6 *)
557 				wsi->dns_results_next->ai_addr)->sin6_scope_id;
558 		sa46.sa6.sin6_flowinfo = ((struct sockaddr_in6 *)
559 				wsi->dns_results_next->ai_addr)->sin6_flowinfo;
560 		sa46.sa6.sin6_port = htons(port);
561 		lws_write_numeric_address((uint8_t *)&sa46.sa6.sin6_addr,
562 				16, ni, sizeof(ni));
563 		lwsl_info("%s: %s ipv6 %s\n", __func__, ads, ni);
564 #else
565 		goto try_next_result;	/* ipv4 only can't use this */
566 #endif
567 		break;
568 	}
569 
570 #if defined(LWS_WITH_UNIX_SOCK)
571 ads_known:
572 #endif
573 
574 	/* now we decided on ipv4 or ipv6, set the port and create socket*/
575 
576 	if (!lws_socket_is_valid(wsi->desc.sockfd)) {
577 
578 		if (wsi->context->event_loop_ops->check_client_connect_ok &&
579 		    wsi->context->event_loop_ops->check_client_connect_ok(wsi)) {
580 			cce = "waiting for event loop watcher to close";
581 			goto oom4;
582 		}
583 
584 #if defined(LWS_WITH_UNIX_SOCK)
585 		if (wsi->unix_skt)
586 			wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
587 		else
588 #endif
589 			wsi->desc.sockfd = socket(sa46.sa4.sin_family,
590 						  SOCK_STREAM, 0);
591 
592 		if (!lws_socket_is_valid(wsi->desc.sockfd)) {
593 			lwsl_warn("Unable to open socket\n");
594 			goto try_next_result;
595 		}
596 
597 		if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd,
598 #if defined(LWS_WITH_UNIX_SOCK)
599 						wsi->unix_skt)) {
600 #else
601 						0)) {
602 #endif
603 			lwsl_err("Failed to set wsi socket options\n");
604 			goto try_next_result_closesock;
605 		}
606 
607 		lwsl_debug("%s: %p: WAITING_CONNECT\n", __func__, wsi);
608 		lwsi_set_state(wsi, LRS_WAITING_CONNECT);
609 
610 		if (wsi->context->event_loop_ops->sock_accept)
611 			if (wsi->context->event_loop_ops->sock_accept(wsi))
612 				goto try_next_result_closesock;
613 
614 		if (__insert_wsi_socket_into_fds(wsi->context, wsi))
615 			goto try_next_result_closesock;
616 
617 		if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
618 			goto try_next_result_fds;
619 
620 		/*
621 		 * Past here, we can't simply free the structs as error
622 		 * handling as oom4 does.
623 		 *
624 		 * We can run the whole close flow, or unpick the fds inclusion
625 		 * and anything else we have done.
626 		 */
627 		wsi->oom4 = 1;
628 		if (!wsi->protocol)
629 			wsi->protocol = &wsi->vhost->protocols[0];
630 
631 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
632 				wsi->context->timeout_secs);
633 
634 		iface = lws_wsi_client_stash_item(wsi, CIS_IFACE,
635 						  _WSI_TOKEN_CLIENT_IFACE);
636 
637 		if (iface && *iface) {
638 			m = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0,
639 					    iface, wsi->ipv6);
640 			if (m < 0)
641 				goto try_next_result_fds;
642 		}
643 	}
644 
645 #if defined(LWS_WITH_UNIX_SOCK)
646 	if (wsi->unix_skt) {
647 		psa = (const struct sockaddr *)&sau;
648 		n = sizeof(sau);
649 	} else
650 #endif
651 
652 	if (!psa) /* coverity */
653 		goto try_next_result_fds;
654 
655 	/*
656 	 * The actual connection attempt
657 	 */
658 
659 #if defined(LWS_WITH_DETAILED_LATENCY)
660 	wsi->detlat.earliest_write_req =
661 		wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
662 #endif
663 
664 	m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa, n);
665 	if (m == -1) {
666 		int errno_copy = LWS_ERRNO;
667 
668 		lwsl_debug("%s: connect says errno: %d\n", __func__, errno_copy);
669 
670 		if (errno_copy != LWS_EALREADY &&
671 		    errno_copy != LWS_EINPROGRESS &&
672 		    errno_copy != LWS_EWOULDBLOCK
673 #ifdef _WIN32
674 			&& errno_copy != WSAEINVAL
675                        && errno_copy != WSAEISCONN
676 #endif
677 		) {
678 #if defined(_DEBUG)
679 			char nads[48];
680 			lws_sa46_write_numeric_address(&sa46, nads, sizeof(nads));
681 			lwsl_info("%s: Connect failed: %s port %d\n",
682 				    __func__, nads, port);
683 #endif
684 			goto try_next_result_fds;
685 		}
686 
687 #if defined(WIN32)
688 		if (lws_plat_check_connection_error(wsi))
689 			goto try_next_result_fds;
690                if (errno_copy == WSAEISCONN)
691                        goto conn_good;
692 #endif
693 
694 		/*
695 		 * must do specifically a POLLOUT poll to hear
696 		 * about the connect completion
697 		 */
698 		if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
699 			goto try_next_result_fds;
700 
701 		return wsi;
702 	}
703 
704 conn_good:
705 
706 	lwsl_info("%s: Connection started %p\n", __func__, wsi->dns_results);
707 
708 	/* the tcp connection has happend */
709 
710 #if defined(LWS_WITH_DETAILED_LATENCY)
711 	if (wsi->context->detailed_latency_cb) {
712 		wsi->detlat.type = LDLT_CONNECTION;
713 		wsi->detlat.latencies[LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE] =
714 			lws_now_usecs() -
715 			wsi->detlat.earliest_write_req_pre_write;
716 		wsi->detlat.latencies[LAT_DUR_USERCB] = 0;
717 		lws_det_lat_cb(wsi->context, &wsi->detlat);
718 		wsi->detlat.earliest_write_req =
719 			wsi->detlat.earliest_write_req_pre_write =
720 							lws_now_usecs();
721 	}
722 #endif
723 
724 	lws_addrinfo_clean(wsi);
725 
726 	if (wsi->protocol)
727 		wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
728 					wsi->user_space, NULL, 0);
729 
730 	return lws_client_connect_4_established(wsi, NULL, plen);
731 
732 oom4:
733 	if (lwsi_role_client(wsi) && wsi->protocol /* && lwsi_state_est(wsi) */)
734 		lws_inform_client_conn_fail(wsi,(void *)cce, strlen(cce));
735 
736 	/* take care that we might be inserted in fds already */
737 	if (wsi->position_in_fds_table != LWS_NO_FDS_POS)
738 		goto failed1;
739 
740 	/*
741 	 * We can't be an active client connection any more, if we thought
742 	 * that was what we were going to be doing.  It should be if we are
743 	 * failing by oom4 path, we are still called by
744 	 * lws_client_connect_via_info() and will be returning NULL to that,
745 	 * so nobody else should have had a chance to queue on us.
746 	 */
747 	{
748 		struct lws_vhost *vhost = wsi->vhost;
749 
750 		lws_vhost_lock(vhost);
751 		__lws_free_wsi(wsi);
752 		lws_vhost_unlock(vhost);
753 	}
754 
755 	return NULL;
756 
757 
758 try_next_result_fds:
759 	wsi->oom4 = 0;
760 	__remove_wsi_socket_from_fds(wsi);
761 
762 try_next_result_closesock:
763 	compatible_close(wsi->desc.sockfd);
764 	wsi->desc.sockfd = LWS_SOCK_INVALID;
765 
766 try_next_result:
767 	if (wsi->dns_results_next) {
768 		wsi->dns_results_next = wsi->dns_results_next->ai_next;
769 		if (wsi->dns_results_next)
770 			goto next_result;
771 	}
772 	lws_addrinfo_clean(wsi);
773 	cce = "Unable to connect";
774 
775 //failed:
776 	lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
777 
778 failed1:
779 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
780 
781 	return NULL;
782 }
783 
784 struct lws *
785 lws_client_connect_2_dnsreq(struct lws *wsi)
786 {
787 	struct addrinfo *result = NULL;
788 	const char *meth = NULL, *ads;
789 #if defined(LWS_WITH_IPV6)
790 	struct sockaddr_in addr;
791 	const char *iface;
792 #endif
793 	const char *adsin;
794 	int n, port = 0;
795 	struct lws *w;
796 
797 	if (lwsi_state(wsi) == LRS_WAITING_DNS ||
798 	    lwsi_state(wsi) == LRS_WAITING_CONNECT) {
799 		lwsl_info("%s: LRS_WAITING_DNS / CONNECT\n", __func__);
800 
801 		return wsi;
802 	}
803 
804 	/*
805 	 * The first job is figure out if we want to pipeline on or just join
806 	 * an existing "active connection" to the same place
807 	 */
808 
809 	meth = lws_wsi_client_stash_item(wsi, CIS_METHOD,
810 					 _WSI_TOKEN_CLIENT_METHOD);
811 
812 	/* we only pipeline connections that said it was okay */
813 
814 	if (!wsi->client_pipeline) {
815 		lwsl_debug("%s: new conn on no pipeline flag\n", __func__);
816 
817 		goto solo;
818 	}
819 
820 	/* only pipeline things we associate with being a stream */
821 
822 	if (meth && strcmp(meth, "RAW") && strcmp(meth, "GET") &&
823 		    strcmp(meth, "POST") && strcmp(meth, "PUT") &&
824 		    strcmp(meth, "UDP") && strcmp(meth, "MQTT"))
825 		goto solo;
826 
827 	/* consult active connections to find out disposition */
828 
829 	adsin = lws_wsi_client_stash_item(wsi, CIS_ADDRESS,
830 					  _WSI_TOKEN_CLIENT_PEER_ADDRESS);
831 
832 	switch (lws_vhost_active_conns(wsi, &w, adsin)) {
833 	case ACTIVE_CONNS_SOLO:
834 		break;
835 	case ACTIVE_CONNS_MUXED:
836 		lwsl_notice("%s: ACTIVE_CONNS_MUXED\n", __func__);
837 		if (lwsi_role_h2(wsi)) {
838 
839 			if (wsi->protocol->callback(wsi,
840 						    LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
841 						    wsi->user_space, NULL, 0))
842 				goto failed1;
843 
844 			//lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
845 			//lwsi_set_state(w, LRS_ESTABLISHED);
846 			lws_callback_on_writable(wsi);
847 		}
848 
849 		return wsi;
850 	case ACTIVE_CONNS_QUEUED:
851 		return lws_client_connect_4_established(wsi, w, 0);
852 	}
853 
854 solo:
855 	wsi->addrinfo_idx = 0;
856 
857 	/*
858 	 * clients who will create their own fresh connection keep a copy of
859 	 * the hostname they originally connected to, in case other connections
860 	 * want to use it too
861 	 */
862 
863 	if (!wsi->cli_hostname_copy) {
864 		if (wsi->stash && wsi->stash->cis[CIS_HOST])
865 			wsi->cli_hostname_copy =
866 					lws_strdup(wsi->stash->cis[CIS_HOST]);
867 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
868 		else {
869 			char *pa = lws_hdr_simple_ptr(wsi,
870 					      _WSI_TOKEN_CLIENT_PEER_ADDRESS);
871 			if (pa)
872 				wsi->cli_hostname_copy = lws_strdup(pa);
873 		}
874 #endif
875 	}
876 
877 	/*
878 	 * If we made our own connection, and we're doing a method that can
879 	 * take a pipeline, we are an "active client connection".
880 	 *
881 	 * Add ourselves to the vhost list of those so that others can
882 	 * piggyback on our transaction queue
883 	 */
884 
885 	if (meth && (!strcmp(meth, "RAW") || !strcmp(meth, "GET") ||
886 		     !strcmp(meth, "POST") || !strcmp(meth, "PUT") ||
887 		     !strcmp(meth, "MQTT")) &&
888 	    lws_dll2_is_detached(&wsi->dll2_cli_txn_queue) &&
889 	    lws_dll2_is_detached(&wsi->dll_cli_active_conns)) {
890 		lws_vhost_lock(wsi->vhost);
891 		lwsl_info("%s: adding active conn %p\n", __func__, wsi);
892 		/* caution... we will have to unpick this on oom4 path */
893 		lws_dll2_add_head(&wsi->dll_cli_active_conns,
894 				 &wsi->vhost->dll_cli_active_conns_owner);
895 		lws_vhost_unlock(wsi->vhost);
896 	}
897 
898 	/*
899 	 * unix socket destination?
900 	 */
901 
902 	if (wsi->stash)
903 		ads = wsi->stash->cis[CIS_ADDRESS];
904 	else
905 		ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
906 #if defined(LWS_WITH_UNIX_SOCK)
907 	if (*ads == '+') {
908 		wsi->unix_skt = 1;
909 		n = 0;
910 		goto next_step;
911 	}
912 #endif
913 
914 	/*
915 	 * start off allowing ipv6 on connection if vhost allows it
916 	 */
917 	wsi->ipv6 = LWS_IPV6_ENABLED(wsi->vhost);
918 #ifdef LWS_WITH_IPV6
919 	if (wsi->stash)
920 		iface = wsi->stash->cis[CIS_IFACE];
921 	else
922 		iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
923 
924 	if (wsi->ipv6 && iface &&
925 	    inet_pton(AF_INET, iface, &addr.sin_addr) == 1) {
926 		lwsl_notice("%s: client connection forced to IPv4\n", __func__);
927 		wsi->ipv6 = 0;
928 	}
929 #endif
930 
931 #if defined(LWS_WITH_DETAILED_LATENCY)
932 	if (lwsi_state(wsi) == LRS_WAITING_DNS &&
933 	    wsi->context->detailed_latency_cb) {
934 		wsi->detlat.type = LDLT_NAME_RESOLUTION;
935 		wsi->detlat.latencies[LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE] =
936 			lws_now_usecs() -
937 			wsi->detlat.earliest_write_req_pre_write;
938 		wsi->detlat.latencies[LAT_DUR_USERCB] = 0;
939 		lws_det_lat_cb(wsi->context, &wsi->detlat);
940 		wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
941 	}
942 #endif
943 
944 #if defined(LWS_CLIENT_HTTP_PROXYING) && \
945 	(defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
946 
947 	/* Decide what it is we need to connect to:
948 	 *
949 	 * Priority 1: connect to http proxy */
950 
951 	if (wsi->vhost->http.http_proxy_port) {
952 		ads = wsi->vhost->http.http_proxy_address;
953 		port = wsi->vhost->http.http_proxy_port;
954 #else
955 		if (0) {
956 #endif
957 
958 #if defined(LWS_WITH_SOCKS5)
959 
960 	/* Priority 2: Connect to SOCK5 Proxy */
961 
962 	} else if (wsi->vhost->socks_proxy_port) {
963 		lwsl_client("Sending SOCKS Greeting\n");
964 		ads = wsi->vhost->socks_proxy_address;
965 		port = wsi->vhost->socks_proxy_port;
966 #endif
967 	} else {
968 
969 		/* Priority 3: Connect directly */
970 
971 		/* ads already set */
972 		port = wsi->c_port;
973 	}
974 
975 	/*
976 	 * prepare the actual connection
977 	 * to whatever we decided to connect to
978 	 */
979 	lwsi_set_state(wsi, LRS_WAITING_DNS);
980 
981 	lwsl_info("%s: %p: lookup %s:%u\n", __func__, wsi, ads, port);
982 	(void)port;
983 
984 #if defined(LWS_WITH_DETAILED_LATENCY)
985 	wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
986 #endif
987 #if !defined(LWS_WITH_SYS_ASYNC_DNS)
988 	if (wsi->dns_results)
989 		n = 0;
990 	else
991 		n = lws_getaddrinfo46(wsi, ads, &result);
992 #else
993 	lwsi_set_state(wsi, LRS_WAITING_DNS);
994 	/* this is either FAILED, CONTINUING, or already called connect_4 */
995 
996 	n = lws_async_dns_query(wsi->context, wsi->tsi, ads, LWS_ADNS_RECORD_A,
997 				lws_client_connect_3_connect, wsi, NULL);
998 	if (n == LADNS_RET_FAILED_WSI_CLOSED)
999 		return NULL;
1000 
1001 	if (n == LADNS_RET_FAILED)
1002 		goto failed1;
1003 
1004 	return wsi;
1005 #endif
1006 
1007 #if defined(LWS_WITH_UNIX_SOCK)
1008 next_step:
1009 #endif
1010 	return lws_client_connect_3_connect(wsi, ads, result, n, NULL);
1011 
1012 //#if defined(LWS_WITH_SYS_ASYNC_DNS)
1013 failed1:
1014 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
1015 
1016 	return NULL;
1017 //#endif
1018 }
1019 
1020 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1021 
1022 static uint8_t hnames2[] = {
1023 	_WSI_TOKEN_CLIENT_ORIGIN,
1024 	_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
1025 	_WSI_TOKEN_CLIENT_METHOD,
1026 	_WSI_TOKEN_CLIENT_IFACE,
1027 	_WSI_TOKEN_CLIENT_ALPN
1028 };
1029 
1030 /**
1031  * lws_client_reset() - retarget a connected wsi to start over with a new
1032  * 			connection (ie, redirect)
1033  *			this only works if still in HTTP, ie, not upgraded yet
1034  * wsi:		connection to reset
1035  * address:	network address of the new server
1036  * port:	port to connect to
1037  * path:	uri path to connect to on the new server
1038  * host:	host header to send to the new server
1039  */
1040 struct lws *
1041 lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
1042 		 const char *path, const char *host, char weak)
1043 {
1044 #if defined(LWS_ROLE_WS)
1045 	struct _lws_websocket_related *ws;
1046 #endif
1047 	char *stash, *p;
1048 	struct lws *wsi;
1049 	size_t size = 0;
1050 	int n;
1051 
1052 	if (!pwsi)
1053 		return NULL;
1054 
1055 	wsi = *pwsi;
1056 
1057 	lwsl_debug("%s: wsi %p: redir %d: %s\n", __func__, wsi, wsi->redirects,
1058 			address);
1059 
1060 	if (wsi->redirects == 3) {
1061 		lwsl_err("%s: Too many redirects\n", __func__);
1062 		return NULL;
1063 	}
1064 	wsi->redirects++;
1065 
1066 	/*
1067 	 * goal is to close our role part, close the sockfd, detach the ah
1068 	 * but leave our wsi extant and still bound to whatever vhost it was
1069 	 */
1070 
1071 	for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++)
1072 		size += lws_hdr_total_length(wsi, hnames2[n]) + (size_t)1;
1073 
1074 	if (size < (size_t)lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI) + 1)
1075 		size = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI) + (size_t)1;
1076 
1077 	/*
1078 	 * The incoming address and host can be from inside the existing ah
1079 	 * we are going to detach and reattch
1080 	 */
1081 
1082 	size += strlen(path) + 1 + strlen(address) + 1 + strlen(host) + 1 + 1;
1083 
1084 	p = stash = lws_malloc(size, __func__);
1085 	if (!stash)
1086 		return NULL;
1087 
1088 	/*
1089 	 * _WSI_TOKEN_CLIENT_ORIGIN,
1090 	 * _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
1091 	 * _WSI_TOKEN_CLIENT_METHOD,
1092 	 * _WSI_TOKEN_CLIENT_IFACE,
1093 	 * _WSI_TOKEN_CLIENT_ALPN
1094 	 * address
1095 	 * host
1096 	 * path
1097 	 */
1098 
1099 	for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++)
1100 		if (lws_hdr_total_length(wsi, hnames2[n])) {
1101 			memcpy(p, lws_hdr_simple_ptr(wsi, hnames2[n]), (size_t)(
1102 			       lws_hdr_total_length(wsi, hnames2[n]) + 1));
1103 			p += (size_t)(lws_hdr_total_length(wsi, hnames2[n]) + 1);
1104 		} else
1105 			*p++ = '\0';
1106 
1107 	memcpy(p, address, strlen(address) + (size_t)1);
1108 	address = p;
1109 	p += strlen(address) + 1;
1110 	memcpy(p, host, strlen(host) + (size_t)1);
1111 	host = p;
1112 	p += strlen(host) + 1;
1113 	memcpy(p, path, strlen(path) + (size_t)1);
1114 	path = p;
1115 
1116 	if (!port) {
1117 		lwsl_info("%s: forcing port 443\n", __func__);
1118 
1119 		port = 443;
1120 		ssl = 1;
1121 	}
1122 
1123 	lwsl_info("redirect ads='%s', port=%d, path='%s', ssl = %d, pifds %d\n",
1124 		   address, port, path, ssl, wsi->position_in_fds_table);
1125 
1126 	__remove_wsi_socket_from_fds(wsi);
1127 #if defined(LWS_ROLE_WS)
1128 	if (weak) {
1129 		ws = wsi->ws;
1130 		wsi->ws = NULL;
1131 	}
1132 #endif
1133 	__lws_reset_wsi(wsi); /* detaches ah here */
1134 #if defined(LWS_ROLE_WS)
1135 	if (weak)
1136 		wsi->ws = ws;
1137 #endif
1138 	wsi->client_pipeline = 1;
1139 
1140 	/* close the connection by hand */
1141 
1142 #if defined(LWS_WITH_TLS)
1143 	lws_ssl_close(wsi);
1144 #endif
1145 
1146 	if (wsi->role_ops && wsi->role_ops->close_kill_connection)
1147 		wsi->role_ops->close_kill_connection(wsi, 1);
1148 
1149 	if (wsi->context->event_loop_ops->close_handle_manually)
1150 		wsi->context->event_loop_ops->close_handle_manually(wsi);
1151 	else
1152 		if (wsi->desc.sockfd != LWS_SOCK_INVALID)
1153 			compatible_close(wsi->desc.sockfd);
1154 
1155 #if defined(LWS_WITH_TLS)
1156 	if (!ssl)
1157 		wsi->tls.use_ssl &= ~LCCSCF_USE_SSL;
1158 	else
1159 		wsi->tls.use_ssl |= LCCSCF_USE_SSL;
1160 #else
1161 	if (ssl) {
1162 		lwsl_err("%s: not configured for ssl\n", __func__);
1163 		goto bail;
1164 	}
1165 #endif
1166 
1167 	if (wsi->protocol && wsi->role_ops && wsi->protocol_bind_balance) {
1168 		wsi->protocol->callback(wsi,
1169 				wsi->role_ops->protocol_unbind_cb[
1170 				       !!lwsi_role_server(wsi)],
1171 				       wsi->user_space, (void *)__func__, 0);
1172 
1173 		wsi->protocol_bind_balance = 0;
1174 	}
1175 
1176 	wsi->desc.sockfd = LWS_SOCK_INVALID;
1177 	lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED, &role_ops_h1);
1178 //	wsi->protocol = NULL;
1179 	if (wsi->protocol)
1180 		lws_bind_protocol(wsi, wsi->protocol, "client_reset");
1181 	wsi->pending_timeout = NO_PENDING_TIMEOUT;
1182 	wsi->c_port = port;
1183 	wsi->hdr_parsing_completed = 0;
1184 
1185 	if (lws_header_table_attach(wsi, 0)) {
1186 		lwsl_err("%s: failed to get ah\n", __func__);
1187 		goto bail;
1188 	}
1189 	//_lws_header_table_reset(wsi->http.ah);
1190 
1191 	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
1192 		goto bail;
1193 
1194 	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
1195 		goto bail;
1196 
1197 	/*
1198 	 * _WSI_TOKEN_CLIENT_ORIGIN,
1199 	 * _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
1200 	 * _WSI_TOKEN_CLIENT_METHOD,
1201 	 * _WSI_TOKEN_CLIENT_IFACE,
1202 	 * _WSI_TOKEN_CLIENT_ALPN
1203 	 * address
1204 	 * host
1205 	 * path
1206 	 */
1207 
1208 	p = stash;
1209 	for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++) {
1210 		if (lws_hdr_simple_create(wsi, hnames2[n], p))
1211 			goto bail;
1212 		p += lws_hdr_total_length(wsi, hnames2[n]) + (size_t)1;
1213 	}
1214 
1215 	stash[0] = '/';
1216 	memmove(&stash[1], path, size - 1 < strlen(path) + 1 ?
1217 					size - 1 : strlen(path) + (size_t)1);
1218 	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash))
1219 		goto bail;
1220 
1221 	lws_free_set_NULL(stash);
1222 
1223 #if defined(LWS_WITH_HTTP2)
1224 	if (wsi->client_mux_substream)
1225 		wsi->h2.END_STREAM = wsi->h2.END_HEADERS = 0;
1226 #endif
1227 
1228 	*pwsi = lws_client_connect_2_dnsreq(wsi);
1229 
1230 	return *pwsi;
1231 
1232 bail:
1233 	lws_free_set_NULL(stash);
1234 
1235 	return NULL;
1236 }
1237 
1238 #if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
1239 hubbub_error
1240 html_parser_cb(const hubbub_token *token, void *pw)
1241 {
1242 	struct lws_rewrite *r = (struct lws_rewrite *)pw;
1243 	char buf[1024], *start = buf + LWS_PRE, *p = start,
1244 	     *end = &buf[sizeof(buf) - 1], dotstar[128];
1245 	size_t i;
1246 
1247 	switch (token->type) {
1248 	case HUBBUB_TOKEN_DOCTYPE:
1249 
1250 		lws_strnncpy(dotstar, token->data.doctype.name.ptr,
1251 			     token->data.doctype.name.len, sizeof(dotstar));
1252 
1253 		p += lws_snprintf(p, end - p, "<!DOCTYPE %s %s ",
1254 				  dotstar, token->data.doctype.force_quirks ?
1255 						"(force-quirks) " : "");
1256 
1257 		if (token->data.doctype.public_missing)
1258 			lwsl_debug("\tpublic: missing\n");
1259 		else {
1260 			lws_strnncpy(dotstar, token->data.doctype.public_id.ptr,
1261 				     token->data.doctype.public_id.len,
1262 				     sizeof(dotstar));
1263 			p += lws_snprintf(p, end - p, "PUBLIC \"%s\"\n",
1264 					  dotstar);
1265 		}
1266 
1267 		if (token->data.doctype.system_missing)
1268 			lwsl_debug("\tsystem: missing\n");
1269 		else {
1270 			lws_strnncpy(dotstar, token->data.doctype.system_id.ptr,
1271 				     token->data.doctype.system_id.len,
1272 				     sizeof(dotstar));
1273 			p += lws_snprintf(p, end - p, " \"%s\">\n", dotstar);
1274 		}
1275 
1276 		break;
1277 	case HUBBUB_TOKEN_START_TAG:
1278 		lws_strnncpy(dotstar, token->data.tag.name.ptr,
1279 			     token->data.tag.name.len, sizeof(dotstar));
1280 		p += lws_snprintf(p, end - p, "<%s", dotstar);
1281 
1282 /*				(token->data.tag.self_closing) ?
1283 						"(self-closing) " : "",
1284 				(token->data.tag.n_attributes > 0) ?
1285 						"attributes:" : "");
1286 */
1287 		for (i = 0; i < token->data.tag.n_attributes; i++) {
1288 			if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
1289 			    !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
1290 			    !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
1291 				const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
1292 				int plen = (int) token->data.tag.attributes[i].value.len;
1293 
1294 				if (strncmp(pp, "http:", 5) && strncmp(pp, "https:", 6)) {
1295 
1296 					if (!hstrcmp(&token->data.tag.attributes[i].value,
1297 						     r->from, r->from_len)) {
1298 						pp += r->from_len;
1299 						plen -= r->from_len;
1300 					}
1301 					lws_strnncpy(dotstar,
1302 						token->data.tag.attributes[i].name.ptr,
1303 						token->data.tag.attributes[i].name.len,
1304 						sizeof(dotstar));
1305 
1306 					p += lws_snprintf(p, end - p, " %s=\"%s",
1307 							  dotstar, r->to);
1308 					lws_strnncpy(dotstar, pp, plen, sizeof(dotstar));
1309 					p += lws_snprintf(p, end - p, " /%s\"", dotstar);
1310 					continue;
1311 				}
1312 			}
1313 
1314 			lws_strnncpy(dotstar,
1315 				token->data.tag.attributes[i].name.ptr,
1316 				token->data.tag.attributes[i].name.len,
1317 				sizeof(dotstar));
1318 
1319 			p += lws_snprintf(p, end - p, " %s=\"", dotstar);
1320 			lws_strnncpy(dotstar,
1321 				token->data.tag.attributes[i].value.ptr,
1322 				token->data.tag.attributes[i].value.len,
1323 				sizeof(dotstar));
1324 			p += lws_snprintf(p, end - p, "%s\"", dotstar);
1325 		}
1326 		p += lws_snprintf(p, end - p, ">");
1327 		break;
1328 	case HUBBUB_TOKEN_END_TAG:
1329 		lws_strnncpy(dotstar, token->data.tag.name.ptr,
1330 			     token->data.tag.name.len, sizeof(dotstar));
1331 		p += lws_snprintf(p, end - p, "</%s", dotstar);
1332 /*
1333 				(token->data.tag.self_closing) ?
1334 						"(self-closing) " : "",
1335 				(token->data.tag.n_attributes > 0) ?
1336 						"attributes:" : "");
1337 */
1338 		for (i = 0; i < token->data.tag.n_attributes; i++) {
1339 			lws_strnncpy(dotstar,
1340 				     token->data.tag.attributes[i].name.ptr,
1341 				     token->data.tag.attributes[i].name.len,
1342 				     sizeof(dotstar));
1343 			p += lws_snprintf(p, end - p, " %s='", dotstar);
1344 			lws_strnncpy(dotstar,
1345 				     token->data.tag.attributes[i].value.ptr,
1346 				     token->data.tag.attributes[i].value.len,
1347 				     sizeof(dotstar));
1348 			p += lws_snprintf(p, end - p, "%s'\n", dotstar);
1349 		}
1350 		p += lws_snprintf(p, end - p, ">");
1351 		break;
1352 	case HUBBUB_TOKEN_COMMENT:
1353 		lws_strnncpy(dotstar, token->data.comment.ptr,
1354 			     token->data.comment.len, sizeof(dotstar));
1355 		p += lws_snprintf(p, end - p, "<!-- %s -->\n",  dotstar);
1356 		break;
1357 	case HUBBUB_TOKEN_CHARACTER:
1358 		if (token->data.character.len == 1) {
1359 			if (*token->data.character.ptr == '<') {
1360 				p += lws_snprintf(p, end - p, "&lt;");
1361 				break;
1362 			}
1363 			if (*token->data.character.ptr == '>') {
1364 				p += lws_snprintf(p, end - p, "&gt;");
1365 				break;
1366 			}
1367 			if (*token->data.character.ptr == '&') {
1368 				p += lws_snprintf(p, end - p, "&amp;");
1369 				break;
1370 			}
1371 		}
1372 		lws_strnncpy(dotstar, token->data.character.ptr,
1373 			     token->data.character.len, sizeof(dotstar));
1374 		p += lws_snprintf(p, end - p, "%s", dotstar);
1375 		break;
1376 	case HUBBUB_TOKEN_EOF:
1377 		p += lws_snprintf(p, end - p, "\n");
1378 		break;
1379 	}
1380 
1381 	if (r->wsi->protocol_bind_balance &&
1382 	    user_callback_handle_rxflow(r->wsi->protocol->callback,
1383 			r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
1384 			r->wsi->user_space, start, p - start))
1385 		return -1;
1386 
1387 	return HUBBUB_OK;
1388 }
1389 #endif
1390 
1391 #endif
1392 
1393 static const uint8_t hnames[] = {
1394 	_WSI_TOKEN_CLIENT_PEER_ADDRESS,
1395 	_WSI_TOKEN_CLIENT_URI,
1396 	_WSI_TOKEN_CLIENT_HOST,
1397 	_WSI_TOKEN_CLIENT_ORIGIN,
1398 	_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
1399 	_WSI_TOKEN_CLIENT_METHOD,
1400 	_WSI_TOKEN_CLIENT_IFACE,
1401 	_WSI_TOKEN_CLIENT_ALPN
1402 };
1403 
1404 struct lws *
1405 lws_http_client_connect_via_info2(struct lws *wsi)
1406 {
1407 	struct client_info_stash *stash = wsi->stash;
1408 	int n;
1409 
1410 	lwsl_debug("%s: %p (stash %p)\n", __func__, wsi, stash);
1411 
1412 	if (!stash)
1413 		return wsi;
1414 
1415 	wsi->opaque_user_data = wsi->stash->opaque_user_data;
1416 
1417 	if (stash->cis[CIS_METHOD] && (!strcmp(stash->cis[CIS_METHOD], "RAW") ||
1418 				      !strcmp(stash->cis[CIS_METHOD], "MQTT")))
1419 		goto no_ah;
1420 
1421 	/*
1422 	 * we're not necessarily in a position to action these right away,
1423 	 * stash them... we only need during connect phase so into a temp
1424 	 * allocated stash
1425 	 */
1426 	for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames); n++)
1427 		if (hnames[n] && stash->cis[n]) {
1428 			if (lws_hdr_simple_create(wsi, hnames[n], stash->cis[n]))
1429 				goto bail1;
1430 		}
1431 
1432 #if defined(LWS_WITH_SOCKS5)
1433 	if (!wsi->vhost->socks_proxy_port)
1434 		lws_free_set_NULL(wsi->stash);
1435 #endif
1436 
1437 no_ah:
1438 	wsi->context->count_wsi_allocated++;
1439 
1440 	return lws_client_connect_2_dnsreq(wsi);
1441 
1442 bail1:
1443 #if defined(LWS_WITH_SOCKS5)
1444 	if (!wsi->vhost->socks_proxy_port)
1445 		lws_free_set_NULL(wsi->stash);
1446 #endif
1447 
1448 	return NULL;
1449 }
1450