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