1 #include "private-libwebsockets.h"
4 lws_client_connect_2(struct lws *wsi)
7 struct sockaddr_in6 server_addr6;
8 struct addrinfo hints, *result;
10 struct lws_context *context = wsi->context;
11 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
12 struct sockaddr_in server_addr4;
13 struct lws_pollfd pfd;
15 const char *cce = "", *iface;
19 lwsl_client("%s\n", __func__);
22 cce = "ah was NULL at cc2";
23 lwsl_err("%s\n", cce);
30 if (wsi->vhost->http_proxy_port) {
31 plen = sprintf((char *)pt->serv_buf,
32 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
33 "User-agent: libwebsockets\x0d\x0a",
34 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
37 if (wsi->vhost->proxy_basic_auth_token[0])
38 plen += sprintf((char *)pt->serv_buf + plen,
39 "Proxy-authorization: basic %s\x0d\x0a",
40 wsi->vhost->proxy_basic_auth_token);
42 plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
43 ads = wsi->vhost->http_proxy_address;
46 if (LWS_IPV6_ENABLED(wsi->vhost)) {
47 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
48 server_addr6.sin6_port = htons(wsi->vhost->http_proxy_port);
51 server_addr4.sin_port = htons(wsi->vhost->http_proxy_port);
54 #if defined(LWS_WITH_SOCKS5)
56 else if (wsi->vhost->socks_proxy_port) {
57 socks_generate_msg(wsi, SOCKS_MSG_GREETING, (size_t *)&plen);
58 lwsl_client("%s\n", "Sending SOCKS Greeting.");
60 ads = wsi->vhost->socks_proxy_address;
63 if (LWS_IPV6_ENABLED(wsi->vhost)) {
64 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
65 server_addr6.sin6_port = htons(wsi->vhost->socks_proxy_port);
68 server_addr4.sin_port = htons(wsi->vhost->socks_proxy_port);
73 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
75 if (LWS_IPV6_ENABLED(wsi->vhost)) {
76 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
77 server_addr6.sin6_port = htons(wsi->c_port);
80 server_addr4.sin_port = htons(wsi->c_port);
84 * prepare the actual connection (to the proxy, if any)
86 lwsl_notice("%s: %p: address %s\n", __func__, wsi, ads);
89 if (LWS_IPV6_ENABLED(wsi->vhost)) {
90 memset(&hints, 0, sizeof(struct addrinfo));
91 #if !defined(__ANDROID__)
92 hints.ai_family = AF_INET6;
93 hints.ai_flags = AI_V4MAPPED;
95 n = getaddrinfo(ads, NULL, &hints, &result);
98 lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
100 lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
102 cce = "getaddrinfo (ipv6) failed";
106 server_addr6.sin6_family = AF_INET6;
107 switch (result->ai_family) {
108 #if defined(__ANDROID__)
110 /* map IPv4 to IPv6 */
111 bzero((char *)&server_addr6.sin6_addr,
112 sizeof(struct in6_addr));
113 server_addr6.sin6_addr.s6_addr[10] = 0xff;
114 server_addr6.sin6_addr.s6_addr[11] = 0xff;
115 memcpy(&server_addr6.sin6_addr.s6_addr[12],
116 &((struct sockaddr_in *)result->ai_addr)->sin_addr,
117 sizeof(struct in_addr));
121 memcpy(&server_addr6.sin6_addr,
122 &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
123 sizeof(struct in6_addr));
124 server_addr6.sin6_scope_id = ((struct sockaddr_in6 *)result->ai_addr)->sin6_scope_id;
125 server_addr6.sin6_flowinfo = ((struct sockaddr_in6 *)result->ai_addr)->sin6_flowinfo;
128 lwsl_err("Unknown address family\n");
129 freeaddrinfo(result);
130 cce = "unknown address family";
134 freeaddrinfo(result);
138 struct addrinfo ai, *res, *result = NULL;
142 memset (&ai, 0, sizeof ai);
143 ai.ai_family = PF_UNSPEC;
144 ai.ai_socktype = SOCK_STREAM;
145 ai.ai_flags = AI_CANONNAME;
147 addr_rv = getaddrinfo(ads, NULL, &ai, &result);
151 switch (res->ai_family) {
153 p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
159 #if defined(LWS_FALLBACK_GETHOSTBYNAME)
160 } else if (addr_rv == EAI_SYSTEM) {
161 struct hostent *host;
163 lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
164 host = gethostbyname(ads);
168 lwsl_err("gethostbyname failed\n");
169 cce = "gethostbyname (ipv4) failed";
174 lwsl_err("getaddrinfo failed\n");
175 cce = "getaddrinfo (ipv4) failed";
181 freeaddrinfo(result);
182 lwsl_err("Couldn't identify address\n");
183 cce = "unable to lookup address";
187 server_addr4.sin_family = AF_INET;
188 server_addr4.sin_addr = *((struct in_addr *)p);
189 bzero(&server_addr4.sin_zero, 8);
191 freeaddrinfo(result);
194 if (!lws_socket_is_valid(wsi->desc.sockfd)) {
197 if (LWS_IPV6_ENABLED(wsi->vhost))
198 wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
201 wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
203 if (!lws_socket_is_valid(wsi->desc.sockfd)) {
204 lwsl_warn("Unable to open socket\n");
205 cce = "unable to open socket";
209 if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
210 lwsl_err("Failed to set wsi socket options\n");
211 compatible_close(wsi->desc.sockfd);
212 cce = "set socket opts failed";
216 wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
218 lws_libev_accept(wsi, wsi->desc);
219 lws_libuv_accept(wsi, wsi->desc);
220 lws_libevent_accept(wsi, wsi->desc);
221 if (insert_wsi_socket_into_fds(context, wsi)) {
222 compatible_close(wsi->desc.sockfd);
223 cce = "insert wsi failed";
227 lws_change_pollfd(wsi, 0, LWS_POLLIN);
230 * past here, we can't simply free the structs as error
231 * handling as oom4 does. We have to run the whole close flow.
235 wsi->protocol = &wsi->vhost->protocols[0];
237 wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
238 wsi->user_space, NULL, 0);
240 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
243 iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
246 n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, iface);
248 cce = "unable to bind socket";
255 if (LWS_IPV6_ENABLED(wsi->vhost)) {
256 v = (struct sockaddr *)&server_addr6;
257 n = sizeof(struct sockaddr_in6);
261 v = (struct sockaddr *)&server_addr4;
262 n = sizeof(struct sockaddr);
265 if (connect(wsi->desc.sockfd, v, n) == -1 ||
266 LWS_ERRNO == LWS_EISCONN) {
267 if (LWS_ERRNO == LWS_EALREADY ||
268 LWS_ERRNO == LWS_EINPROGRESS ||
269 LWS_ERRNO == LWS_EWOULDBLOCK
271 || LWS_ERRNO == WSAEINVAL
274 lwsl_client("nonblocking connect retry (errno = %d)\n",
277 if (lws_plat_check_connection_error(wsi)) {
278 cce = "socket connect failed";
283 * must do specifically a POLLOUT poll to hear
284 * about the connect completion
286 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
287 cce = "POLLOUT set failed";
294 if (LWS_ERRNO != LWS_EISCONN) {
295 lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
296 cce = "connect failed";
301 lwsl_client("connected\n");
303 /* we are connected to server, or proxy */
306 if (wsi->vhost->http_proxy_port) {
309 * OK from now on we talk via the proxy, so connect to that
311 * (will overwrite existing pointer,
312 * leaving old string/frag there but unreferenced)
314 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
315 wsi->vhost->http_proxy_address))
317 wsi->c_port = wsi->vhost->http_proxy_port;
319 n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
322 lwsl_debug("ERROR writing to proxy socket\n");
323 cce = "proxy write failed";
327 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
330 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
334 #if defined(LWS_WITH_SOCKS5)
336 else if (wsi->vhost->socks_proxy_port) {
337 n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
340 lwsl_debug("ERROR writing greeting to socks proxy"
342 cce = "socks write failed";
346 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
349 wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;
356 * provoke service to issue the handshake directly
357 * we need to do it this way because in the proxy case, this is the
358 * next state and executed only if and when we get a good proxy
359 * response inside the state machine... but notice in SSL case this
360 * may not have sent anything yet with 0 return, and won't until some
361 * many retries from main loop. To stop that becoming endless,
362 * cover with a timeout.
365 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
368 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
369 pfd.fd = wsi->desc.sockfd;
370 pfd.events = LWS_POLLIN;
371 pfd.revents = LWS_POLLIN;
373 n = lws_service_fd(context, &pfd);
375 cce = "first service failed";
378 if (n) /* returns 1 on failure after closing wsi */
384 /* we're closing, losing some rx is OK */
386 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
387 if (wsi->mode == LWSCM_HTTP_CLIENT ||
388 wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
389 wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
390 wsi->vhost->protocols[0].callback(wsi,
391 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
392 wsi->user_space, (void *)cce, strlen(cce));
393 wsi->already_did_cce = 1;
395 /* take care that we might be inserted in fds already */
396 if (wsi->position_in_fds_table != -1)
398 lws_remove_from_timeout_list(wsi);
399 lws_header_table_detach(wsi, 0);
405 wsi->vhost->protocols[0].callback(wsi,
406 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
407 wsi->user_space, (void *)cce, strlen(cce));
408 wsi->already_did_cce = 1;
410 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
416 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
417 * this only works if still in HTTP, ie, not upgraded yet
418 * wsi: connection to reset
419 * address: network address of the new server
420 * port: port to connect to
421 * path: uri path to connect to on the new server
422 * host: host header to send to the new server
424 LWS_VISIBLE struct lws *
425 lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
426 const char *path, const char *host)
428 char origin[300] = "", protocol[300] = "", method[32] = "", iface[16] = "", *p;
429 struct lws *wsi = *pwsi;
431 if (wsi->redirects == 3) {
432 lwsl_err("%s: Too many redirects\n", __func__);
437 #ifdef LWS_OPENSSL_SUPPORT
441 lwsl_err("%s: not configured for ssl\n", __func__);
446 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
448 strncpy(origin, p, sizeof(origin) - 1);
450 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
452 strncpy(protocol, p, sizeof(protocol) - 1);
454 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
456 strncpy(method, p, sizeof(method) - 1);
458 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
460 strncpy(method, p, sizeof(iface) - 1);
462 lwsl_debug("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
463 address, port, path, ssl);
465 /* close the connection by hand */
467 compatible_close(wsi->desc.sockfd);
468 remove_wsi_socket_from_fds(wsi);
470 wsi->desc.sockfd = LWS_SOCK_INVALID;
471 wsi->state = LWSS_CLIENT_UNCONNECTED;
472 wsi->protocol = NULL;
473 wsi->pending_timeout = NO_PENDING_TIMEOUT;
475 wsi->hdr_parsing_completed = 0;
476 _lws_header_table_reset(wsi->u.hdr.ah);
478 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
481 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
485 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
489 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
493 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
498 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
503 strncpy(&origin[1], path, sizeof(origin) - 2);
504 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
507 *pwsi = lws_client_connect_2(wsi);
512 #ifdef LWS_WITH_HTTP_PROXY
514 html_parser_cb(const hubbub_token *token, void *pw)
516 struct lws_rewrite *r = (struct lws_rewrite *)pw;
517 char buf[1024], *start = buf + LWS_PRE, *p = start,
518 *end = &buf[sizeof(buf) - 1];
521 switch (token->type) {
522 case HUBBUB_TOKEN_DOCTYPE:
524 p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
525 (int) token->data.doctype.name.len,
526 token->data.doctype.name.ptr,
527 token->data.doctype.force_quirks ?
528 "(force-quirks) " : "");
530 if (token->data.doctype.public_missing)
531 lwsl_debug("\tpublic: missing\n");
533 p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
534 (int) token->data.doctype.public_id.len,
535 token->data.doctype.public_id.ptr);
537 if (token->data.doctype.system_missing)
538 lwsl_debug("\tsystem: missing\n");
540 p += lws_snprintf(p, end - p, " \"%.*s\">\n",
541 (int) token->data.doctype.system_id.len,
542 token->data.doctype.system_id.ptr);
545 case HUBBUB_TOKEN_START_TAG:
546 p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
547 token->data.tag.name.ptr);
549 /* (token->data.tag.self_closing) ?
550 "(self-closing) " : "",
551 (token->data.tag.n_attributes > 0) ?
554 for (i = 0; i < token->data.tag.n_attributes; i++) {
555 if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
556 !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
557 !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
558 const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
559 int plen = (int) token->data.tag.attributes[i].value.len;
561 if (strncmp(pp, "http:", 5) && strncmp(pp, "https:", 6)) {
563 if (!hstrcmp(&token->data.tag.attributes[i].value,
564 r->from, r->from_len)) {
568 p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
569 (int) token->data.tag.attributes[i].name.len,
570 token->data.tag.attributes[i].name.ptr,
576 p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
577 (int) token->data.tag.attributes[i].name.len,
578 token->data.tag.attributes[i].name.ptr,
579 (int) token->data.tag.attributes[i].value.len,
580 token->data.tag.attributes[i].value.ptr);
582 p += lws_snprintf(p, end - p, ">");
584 case HUBBUB_TOKEN_END_TAG:
585 p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
586 token->data.tag.name.ptr);
588 (token->data.tag.self_closing) ?
589 "(self-closing) " : "",
590 (token->data.tag.n_attributes > 0) ?
593 for (i = 0; i < token->data.tag.n_attributes; i++) {
594 p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
595 (int) token->data.tag.attributes[i].name.len,
596 token->data.tag.attributes[i].name.ptr,
597 (int) token->data.tag.attributes[i].value.len,
598 token->data.tag.attributes[i].value.ptr);
600 p += lws_snprintf(p, end - p, ">");
602 case HUBBUB_TOKEN_COMMENT:
603 p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
604 (int) token->data.comment.len,
605 token->data.comment.ptr);
607 case HUBBUB_TOKEN_CHARACTER:
608 if (token->data.character.len == 1) {
609 if (*token->data.character.ptr == '<') {
610 p += lws_snprintf(p, end - p, "<");
613 if (*token->data.character.ptr == '>') {
614 p += lws_snprintf(p, end - p, ">");
617 if (*token->data.character.ptr == '&') {
618 p += lws_snprintf(p, end - p, "&");
623 p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
624 token->data.character.ptr);
626 case HUBBUB_TOKEN_EOF:
627 p += lws_snprintf(p, end - p, "\n");
631 if (user_callback_handle_rxflow(r->wsi->protocol->callback,
632 r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
633 r->wsi->user_space, start, p - start))
640 LWS_VISIBLE struct lws *
641 lws_client_connect_via_info(struct lws_client_connect_info *i)
644 int v = SPEC_LATEST_SUPPORTED;
645 const struct lws_protocols *p;
647 if (i->context->requested_kill)
650 if (!i->context->protocol_init_done)
651 lws_protocol_init(i->context);
653 wsi = lws_zalloc(sizeof(struct lws));
657 wsi->context = i->context;
658 /* assert the mode and union status (hdr) clearly */
659 lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
660 wsi->desc.sockfd = LWS_SOCK_INVALID;
662 /* 1) fill up the wsi with stuff from the connect_info as far as it
663 * can go. It's because not only is our connection async, we might
664 * not even be able to get ahold of an ah at this point.
667 /* -1 means just use latest supported */
668 if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
669 v = i->ietf_version_or_minus_one;
671 wsi->ietf_spec_revision = v;
672 wsi->user_space = NULL;
673 wsi->state = LWSS_CLIENT_UNCONNECTED;
674 wsi->pending_timeout = NO_PENDING_TIMEOUT;
675 wsi->position_in_fds_table = -1;
676 wsi->c_port = i->port;
677 wsi->vhost = i->vhost;
679 wsi->vhost = i->context->vhost_list;
681 wsi->protocol = &wsi->vhost->protocols[0];
683 /* for http[s] connection, allow protocol selection by name */
685 if (i->method && i->vhost && i->protocol) {
686 p = lws_vhost_name_to_protocol(i->vhost, i->protocol);
691 if (wsi && !wsi->user_space && i->userdata) {
692 wsi->user_space_externally_allocated = 1;
693 wsi->user_space = i->userdata;
695 /* if we stay in http, we can assign the user space now,
696 * otherwise do it after the protocol negotiated
699 if (lws_ensure_user_space(wsi))
702 #ifdef LWS_OPENSSL_SUPPORT
703 wsi->use_ssl = i->ssl_connection;
705 if (i->ssl_connection) {
706 lwsl_err("libwebsockets not configured for ssl\n");
711 /* 2) stash the things from connect_info that we can't process without
712 * an ah. Because if no ah, we will go on the ah waiting list and
713 * process those things later (after the connect_info and maybe the
714 * things pointed to have gone out of scope.
717 wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
718 if (!wsi->u.hdr.stash) {
719 lwsl_err("%s: OOM\n", __func__);
723 wsi->u.hdr.stash->origin[0] = '\0';
724 wsi->u.hdr.stash->protocol[0] = '\0';
725 wsi->u.hdr.stash->method[0] = '\0';
726 wsi->u.hdr.stash->iface[0] = '\0';
728 strncpy(wsi->u.hdr.stash->address, i->address,
729 sizeof(wsi->u.hdr.stash->address) - 1);
730 strncpy(wsi->u.hdr.stash->path, i->path,
731 sizeof(wsi->u.hdr.stash->path) - 1);
732 strncpy(wsi->u.hdr.stash->host, i->host,
733 sizeof(wsi->u.hdr.stash->host) - 1);
735 strncpy(wsi->u.hdr.stash->origin, i->origin,
736 sizeof(wsi->u.hdr.stash->origin) - 1);
738 strncpy(wsi->u.hdr.stash->protocol, i->protocol,
739 sizeof(wsi->u.hdr.stash->protocol) - 1);
741 strncpy(wsi->u.hdr.stash->method, i->method,
742 sizeof(wsi->u.hdr.stash->method) - 1);
744 strncpy(wsi->u.hdr.stash->iface, i->iface,
745 sizeof(wsi->u.hdr.stash->iface) - 1);
747 wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
748 wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
749 wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
750 wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
751 wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
752 wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
753 wsi->u.hdr.stash->iface[sizeof(wsi->u.hdr.stash->iface) - 1] = '\0';
758 /* if we went on the waiting list, no probs just return the wsi
759 * when we get the ah, now or later, he will call
760 * lws_client_connect_via_info2() below.
762 if (lws_header_table_attach(wsi, 0) < 0) {
764 * if we failed here, the connection is already closed
771 lwsl_info("%s: created child %p of parent %p\n", __func__,
773 wsi->parent = i->parent_wsi;
774 wsi->sibling_list = i->parent_wsi->child_list;
775 i->parent_wsi->child_list = wsi;
777 #ifdef LWS_WITH_HTTP_PROXY
778 if (i->uri_replace_to)
779 wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
797 lws_client_connect_via_info2(struct lws *wsi)
799 struct client_info_stash *stash = wsi->u.hdr.stash;
805 * we're not necessarily in a position to action these right away,
806 * stash them... we only need during connect phase so u.hdr is fine
808 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
812 /* these only need u.hdr lifetime as well */
814 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
817 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
820 if (stash->origin[0])
821 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
825 * this is a list of protocols we tell the server we're okay with
826 * stash it for later when we compare server response with it
828 if (stash->protocol[0])
829 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
832 if (stash->method[0])
833 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
837 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
841 #if defined(LWS_WITH_SOCKS5)
842 if (!wsi->vhost->socks_proxy_port)
843 lws_free_set_NULL(wsi->u.hdr.stash);
847 * Check with each extension if it is able to route and proxy this
848 * connection for us. For example, an extension like x-google-mux
849 * can handle this and then we don't need an actual socket for this
853 if (lws_ext_cb_all_exts(wsi->context, wsi,
854 LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
855 (void *)stash->address,
857 lwsl_client("lws_client_connect: ext handling conn\n");
860 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
863 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
866 lwsl_client("lws_client_connect: direct conn\n");
867 wsi->context->count_wsi_allocated++;
869 return lws_client_connect_2(wsi);
872 #if defined(LWS_WITH_SOCKS5)
873 if (!wsi->vhost->socks_proxy_port)
874 lws_free_set_NULL(wsi->u.hdr.stash);
880 LWS_VISIBLE struct lws *
881 lws_client_connect_extended(struct lws_context *context, const char *address,
882 int port, int ssl_connection, const char *path,
883 const char *host, const char *origin,
884 const char *protocol, int ietf_version_or_minus_one,
887 struct lws_client_connect_info i;
889 memset(&i, 0, sizeof(i));
894 i.ssl_connection = ssl_connection;
898 i.protocol = protocol;
899 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
900 i.userdata = userdata;
902 return lws_client_connect_via_info(&i);
905 LWS_VISIBLE struct lws *
906 lws_client_connect(struct lws_context *context, const char *address,
907 int port, int ssl_connection, const char *path,
908 const char *host, const char *origin,
909 const char *protocol, int ietf_version_or_minus_one)
911 struct lws_client_connect_info i;
913 memset(&i, 0, sizeof(i));
918 i.ssl_connection = ssl_connection;
922 i.protocol = protocol;
923 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
926 return lws_client_connect_via_info(&i);
929 #if defined(LWS_WITH_SOCKS5)
930 void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
933 struct lws_context *context = wsi->context;
934 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
937 if (type == SOCKS_MSG_GREETING) {
938 /* socks version, version 5 only */
939 pt->serv_buf[len++] = SOCKS_VERSION_5;
940 /* number of methods */
941 pt->serv_buf[len++] = 2;
942 /* username password method */
943 pt->serv_buf[len++] = SOCKS_AUTH_USERNAME_PASSWORD;
944 /* no authentication method */
945 pt->serv_buf[len++] = SOCKS_AUTH_NO_AUTH;
947 else if (type == SOCKS_MSG_USERNAME_PASSWORD) {
949 size_t passwd_len = 0;
951 user_len = strlen(wsi->vhost->socks_user);
952 passwd_len = strlen(wsi->vhost->socks_password);
954 /* the subnegotiation version */
955 pt->serv_buf[len++] = SOCKS_SUBNEGOTIATION_VERSION_1;
956 /* length of the user name */
957 pt->serv_buf[len++] = user_len;
959 strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_user,
960 context->pt_serv_buf_size - len);
962 /* length of the password */
963 pt->serv_buf[len++] = passwd_len;
965 strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_password,
966 context->pt_serv_buf_size - len);
969 else if (type == SOCKS_MSG_CONNECT) {
970 size_t len_index = 0;
972 char *net_buf = (char*)&net_num;
975 pt->serv_buf[len++] = SOCKS_VERSION_5;
977 pt->serv_buf[len++] = SOCKS_COMMAND_CONNECT;
979 pt->serv_buf[len++] = 0;
981 pt->serv_buf[len++] = SOCKS_ATYP_DOMAINNAME;
984 /* the address we tell SOCKS proxy to connect to */
985 strncpy((char *)&(pt->serv_buf[len]), wsi->u.hdr.stash->address,
986 context->pt_serv_buf_size - len);
987 len += strlen(wsi->u.hdr.stash->address);
988 net_num = htons((short)wsi->c_port);
989 /* the port we tell SOCKS proxy to connect to */
990 pt->serv_buf[len++] = net_buf[0];
991 pt->serv_buf[len++] = net_buf[1];
992 /* the length of the address, excluding port */
993 pt->serv_buf[len_index] = strlen(wsi->u.hdr.stash->address);