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, "<");
1361 break;
1362 }
1363 if (*token->data.character.ptr == '>') {
1364 p += lws_snprintf(p, end - p, ">");
1365 break;
1366 }
1367 if (*token->data.character.ptr == '&') {
1368 p += lws_snprintf(p, end - p, "&");
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