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;
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 n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, wsi->vhost->iface);
245 cce = "unable to bind socket";
251 if (LWS_IPV6_ENABLED(wsi->vhost)) {
252 v = (struct sockaddr *)&server_addr6;
253 n = sizeof(struct sockaddr_in6);
257 v = (struct sockaddr *)&server_addr4;
258 n = sizeof(struct sockaddr);
261 if (connect(wsi->desc.sockfd, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
262 if (LWS_ERRNO == LWS_EALREADY ||
263 LWS_ERRNO == LWS_EINPROGRESS ||
264 LWS_ERRNO == LWS_EWOULDBLOCK
266 || LWS_ERRNO == WSAEINVAL
269 lwsl_client("nonblocking connect retry (errno = %d)\n",
272 if (lws_plat_check_connection_error(wsi)) {
273 cce = "socket connect failed";
278 * must do specifically a POLLOUT poll to hear
279 * about the connect completion
281 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
282 cce = "POLLOUT set failed";
289 if (LWS_ERRNO != LWS_EISCONN) {
290 lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
291 cce = "connect failed";
296 lwsl_client("connected\n");
298 /* we are connected to server, or proxy */
301 if (wsi->vhost->http_proxy_port) {
304 * OK from now on we talk via the proxy, so connect to that
306 * (will overwrite existing pointer,
307 * leaving old string/frag there but unreferenced)
309 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
310 wsi->vhost->http_proxy_address))
312 wsi->c_port = wsi->vhost->http_proxy_port;
314 n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
317 lwsl_debug("ERROR writing to proxy socket\n");
318 cce = "proxy write failed";
322 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
325 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
329 #if defined(LWS_WITH_SOCKS5)
331 else if (wsi->vhost->socks_proxy_port) {
332 n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
335 lwsl_debug("ERROR writing greeting to socks proxy"
337 cce = "socks write failed";
341 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
344 wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;
351 * provoke service to issue the handshake directly
352 * we need to do it this way because in the proxy case, this is the
353 * next state and executed only if and when we get a good proxy
354 * response inside the state machine... but notice in SSL case this
355 * may not have sent anything yet with 0 return, and won't until some
356 * many retries from main loop. To stop that becoming endless,
357 * cover with a timeout.
360 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
363 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
364 pfd.fd = wsi->desc.sockfd;
365 pfd.events = LWS_POLLIN;
366 pfd.revents = LWS_POLLIN;
368 n = lws_service_fd(context, &pfd);
370 cce = "first service failed";
373 if (n) /* returns 1 on failure after closing wsi */
379 /* we're closing, losing some rx is OK */
381 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
382 if (wsi->mode == LWSCM_HTTP_CLIENT ||
383 wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
384 wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
385 wsi->vhost->protocols[0].callback(wsi,
386 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
387 wsi->user_space, (void *)cce, strlen(cce));
388 wsi->already_did_cce = 1;
390 /* take care that we might be inserted in fds already */
391 if (wsi->position_in_fds_table != -1)
393 lws_remove_from_timeout_list(wsi);
394 lws_header_table_detach(wsi, 0);
400 wsi->vhost->protocols[0].callback(wsi,
401 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
402 wsi->user_space, (void *)cce, strlen(cce));
403 wsi->already_did_cce = 1;
405 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
411 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
412 * this only works if still in HTTP, ie, not upgraded yet
413 * wsi: connection to reset
414 * address: network address of the new server
415 * port: port to connect to
416 * path: uri path to connect to on the new server
417 * host: host header to send to the new server
419 LWS_VISIBLE struct lws *
420 lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
421 const char *path, const char *host)
423 char origin[300] = "", protocol[300] = "", method[32] = "", *p;
424 struct lws *wsi = *pwsi;
426 if (wsi->redirects == 3) {
427 lwsl_err("%s: Too many redirects\n", __func__);
432 #ifdef LWS_OPENSSL_SUPPORT
436 lwsl_err("%s: not configured for ssl\n", __func__);
441 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
443 strncpy(origin, p, sizeof(origin) - 1);
445 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
447 strncpy(protocol, p, sizeof(protocol) - 1);
449 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
451 strncpy(method, p, sizeof(method) - 1);
453 lwsl_debug("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
454 address, port, path, ssl);
456 /* close the connection by hand */
458 compatible_close(wsi->desc.sockfd);
459 remove_wsi_socket_from_fds(wsi);
461 wsi->desc.sockfd = LWS_SOCK_INVALID;
462 wsi->state = LWSS_CLIENT_UNCONNECTED;
463 wsi->protocol = NULL;
464 wsi->pending_timeout = NO_PENDING_TIMEOUT;
466 wsi->hdr_parsing_completed = 0;
467 _lws_header_table_reset(wsi->u.hdr.ah);
469 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
472 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
476 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
480 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
484 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
489 strncpy(&origin[1], path, sizeof(origin) - 2);
490 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
493 *pwsi = lws_client_connect_2(wsi);
498 #ifdef LWS_WITH_HTTP_PROXY
500 html_parser_cb(const hubbub_token *token, void *pw)
502 struct lws_rewrite *r = (struct lws_rewrite *)pw;
503 char buf[1024], *start = buf + LWS_PRE, *p = start,
504 *end = &buf[sizeof(buf) - 1];
507 switch (token->type) {
508 case HUBBUB_TOKEN_DOCTYPE:
510 p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
511 (int) token->data.doctype.name.len,
512 token->data.doctype.name.ptr,
513 token->data.doctype.force_quirks ?
514 "(force-quirks) " : "");
516 if (token->data.doctype.public_missing)
517 printf("\tpublic: missing\n");
519 p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
520 (int) token->data.doctype.public_id.len,
521 token->data.doctype.public_id.ptr);
523 if (token->data.doctype.system_missing)
524 printf("\tsystem: missing\n");
526 p += lws_snprintf(p, end - p, " \"%.*s\">\n",
527 (int) token->data.doctype.system_id.len,
528 token->data.doctype.system_id.ptr);
531 case HUBBUB_TOKEN_START_TAG:
532 p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
533 token->data.tag.name.ptr);
535 /* (token->data.tag.self_closing) ?
536 "(self-closing) " : "",
537 (token->data.tag.n_attributes > 0) ?
540 for (i = 0; i < token->data.tag.n_attributes; i++) {
541 if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
542 !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
543 !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
544 const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
545 int plen = (int) token->data.tag.attributes[i].value.len;
547 if (!hstrcmp(&token->data.tag.attributes[i].value,
548 r->from, r->from_len)) {
552 p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
553 (int) token->data.tag.attributes[i].name.len,
554 token->data.tag.attributes[i].name.ptr,
559 p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
560 (int) token->data.tag.attributes[i].name.len,
561 token->data.tag.attributes[i].name.ptr,
562 (int) token->data.tag.attributes[i].value.len,
563 token->data.tag.attributes[i].value.ptr);
565 p += lws_snprintf(p, end - p, ">\n");
567 case HUBBUB_TOKEN_END_TAG:
568 p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
569 token->data.tag.name.ptr);
571 (token->data.tag.self_closing) ?
572 "(self-closing) " : "",
573 (token->data.tag.n_attributes > 0) ?
576 for (i = 0; i < token->data.tag.n_attributes; i++) {
577 p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
578 (int) token->data.tag.attributes[i].name.len,
579 token->data.tag.attributes[i].name.ptr,
580 (int) token->data.tag.attributes[i].value.len,
581 token->data.tag.attributes[i].value.ptr);
583 p += lws_snprintf(p, end - p, ">\n");
585 case HUBBUB_TOKEN_COMMENT:
586 p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
587 (int) token->data.comment.len,
588 token->data.comment.ptr);
590 case HUBBUB_TOKEN_CHARACTER:
591 p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
592 token->data.character.ptr);
594 case HUBBUB_TOKEN_EOF:
595 p += lws_snprintf(p, end - p, "\n");
599 if (user_callback_handle_rxflow(r->wsi->protocol->callback,
600 r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
601 r->wsi->user_space, start, p - start))
608 LWS_VISIBLE struct lws *
609 lws_client_connect_via_info(struct lws_client_connect_info *i)
612 int v = SPEC_LATEST_SUPPORTED;
613 const struct lws_protocols *p;
615 if (i->context->requested_kill)
618 if (!i->context->protocol_init_done)
619 lws_protocol_init(i->context);
621 wsi = lws_zalloc(sizeof(struct lws));
625 wsi->context = i->context;
626 /* assert the mode and union status (hdr) clearly */
627 lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
628 wsi->desc.sockfd = LWS_SOCK_INVALID;
630 /* 1) fill up the wsi with stuff from the connect_info as far as it
631 * can go. It's because not only is our connection async, we might
632 * not even be able to get ahold of an ah at this point.
635 /* -1 means just use latest supported */
636 if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
637 v = i->ietf_version_or_minus_one;
639 wsi->ietf_spec_revision = v;
640 wsi->user_space = NULL;
641 wsi->state = LWSS_CLIENT_UNCONNECTED;
642 wsi->pending_timeout = NO_PENDING_TIMEOUT;
643 wsi->position_in_fds_table = -1;
644 wsi->c_port = i->port;
645 wsi->vhost = i->vhost;
647 wsi->vhost = i->context->vhost_list;
649 wsi->protocol = &wsi->vhost->protocols[0];
651 /* for http[s] connection, allow protocol selection by name */
653 if (i->method && i->vhost && i->protocol) {
654 p = lws_vhost_name_to_protocol(i->vhost, i->protocol);
659 if (wsi && !wsi->user_space && i->userdata) {
660 wsi->user_space_externally_allocated = 1;
661 wsi->user_space = i->userdata;
663 /* if we stay in http, we can assign the user space now,
664 * otherwise do it after the protocol negotiated
667 if (lws_ensure_user_space(wsi))
670 #ifdef LWS_OPENSSL_SUPPORT
671 wsi->use_ssl = i->ssl_connection;
673 if (i->ssl_connection) {
674 lwsl_err("libwebsockets not configured for ssl\n");
679 /* 2) stash the things from connect_info that we can't process without
680 * an ah. Because if no ah, we will go on the ah waiting list and
681 * process those things later (after the connect_info and maybe the
682 * things pointed to have gone out of scope.
685 wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
686 if (!wsi->u.hdr.stash) {
687 lwsl_err("%s: OOM\n", __func__);
691 wsi->u.hdr.stash->origin[0] = '\0';
692 wsi->u.hdr.stash->protocol[0] = '\0';
693 wsi->u.hdr.stash->method[0] = '\0';
695 strncpy(wsi->u.hdr.stash->address, i->address,
696 sizeof(wsi->u.hdr.stash->address) - 1);
697 strncpy(wsi->u.hdr.stash->path, i->path,
698 sizeof(wsi->u.hdr.stash->path) - 1);
699 strncpy(wsi->u.hdr.stash->host, i->host,
700 sizeof(wsi->u.hdr.stash->host) - 1);
702 strncpy(wsi->u.hdr.stash->origin, i->origin,
703 sizeof(wsi->u.hdr.stash->origin) - 1);
705 strncpy(wsi->u.hdr.stash->protocol, i->protocol,
706 sizeof(wsi->u.hdr.stash->protocol) - 1);
708 strncpy(wsi->u.hdr.stash->method, i->method,
709 sizeof(wsi->u.hdr.stash->method) - 1);
711 wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
712 wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
713 wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
714 wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
715 wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
716 wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
721 /* if we went on the waiting list, no probs just return the wsi
722 * when we get the ah, now or later, he will call
723 * lws_client_connect_via_info2() below.
725 if (lws_header_table_attach(wsi, 0) < 0) {
727 * if we failed here, the connection is already closed
734 lwsl_info("%s: created child %p of parent %p\n", __func__,
736 wsi->parent = i->parent_wsi;
737 wsi->sibling_list = i->parent_wsi->child_list;
738 i->parent_wsi->child_list = wsi;
740 #ifdef LWS_WITH_HTTP_PROXY
741 if (i->uri_replace_to)
742 wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
760 lws_client_connect_via_info2(struct lws *wsi)
762 struct client_info_stash *stash = wsi->u.hdr.stash;
768 * we're not necessarily in a position to action these right away,
769 * stash them... we only need during connect phase so u.hdr is fine
771 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
775 /* these only need u.hdr lifetime as well */
777 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
780 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
783 if (stash->origin[0])
784 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
788 * this is a list of protocols we tell the server we're okay with
789 * stash it for later when we compare server response with it
791 if (stash->protocol[0])
792 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
795 if (stash->method[0])
796 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
800 #if defined(LWS_WITH_SOCKS5)
801 if (!wsi->vhost->socks_proxy_port)
802 lws_free_set_NULL(wsi->u.hdr.stash);
806 * Check with each extension if it is able to route and proxy this
807 * connection for us. For example, an extension like x-google-mux
808 * can handle this and then we don't need an actual socket for this
812 if (lws_ext_cb_all_exts(wsi->context, wsi,
813 LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
814 (void *)stash->address,
816 lwsl_client("lws_client_connect: ext handling conn\n");
819 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
822 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
825 lwsl_client("lws_client_connect: direct conn\n");
826 wsi->context->count_wsi_allocated++;
828 return lws_client_connect_2(wsi);
831 #if defined(LWS_WITH_SOCKS5)
832 if (!wsi->vhost->socks_proxy_port)
833 lws_free_set_NULL(wsi->u.hdr.stash);
839 LWS_VISIBLE struct lws *
840 lws_client_connect_extended(struct lws_context *context, const char *address,
841 int port, int ssl_connection, const char *path,
842 const char *host, const char *origin,
843 const char *protocol, int ietf_version_or_minus_one,
846 struct lws_client_connect_info i;
848 memset(&i, 0, sizeof(i));
853 i.ssl_connection = ssl_connection;
857 i.protocol = protocol;
858 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
859 i.userdata = userdata;
861 return lws_client_connect_via_info(&i);
864 LWS_VISIBLE struct lws *
865 lws_client_connect(struct lws_context *context, const char *address,
866 int port, int ssl_connection, const char *path,
867 const char *host, const char *origin,
868 const char *protocol, int ietf_version_or_minus_one)
870 struct lws_client_connect_info i;
872 memset(&i, 0, sizeof(i));
877 i.ssl_connection = ssl_connection;
881 i.protocol = protocol;
882 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
885 return lws_client_connect_via_info(&i);
888 #if defined(LWS_WITH_SOCKS5)
889 void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
892 struct lws_context *context = wsi->context;
893 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
896 if (type == SOCKS_MSG_GREETING) {
897 /* socks version, version 5 only */
898 pt->serv_buf[len++] = SOCKS_VERSION_5;
899 /* number of methods */
900 pt->serv_buf[len++] = 2;
901 /* username password method */
902 pt->serv_buf[len++] = SOCKS_AUTH_USERNAME_PASSWORD;
903 /* no authentication method */
904 pt->serv_buf[len++] = SOCKS_AUTH_NO_AUTH;
906 else if (type == SOCKS_MSG_USERNAME_PASSWORD) {
908 size_t passwd_len = 0;
910 user_len = strlen(wsi->vhost->socks_user);
911 passwd_len = strlen(wsi->vhost->socks_password);
913 /* the subnegotiation version */
914 pt->serv_buf[len++] = SOCKS_SUBNEGOTIATION_VERSION_1;
915 /* length of the user name */
916 pt->serv_buf[len++] = user_len;
918 strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_user,
919 context->pt_serv_buf_size - len);
921 /* length of the password */
922 pt->serv_buf[len++] = passwd_len;
924 strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_password,
925 context->pt_serv_buf_size - len);
928 else if (type == SOCKS_MSG_CONNECT) {
929 size_t len_index = 0;
931 char *net_buf = (char*)&net_num;
934 pt->serv_buf[len++] = SOCKS_VERSION_5;
936 pt->serv_buf[len++] = SOCKS_COMMAND_CONNECT;
938 pt->serv_buf[len++] = 0;
940 pt->serv_buf[len++] = SOCKS_ATYP_DOMAINNAME;
943 /* the address we tell SOCKS proxy to connect to */
944 strncpy((char *)&(pt->serv_buf[len]), wsi->u.hdr.stash->address,
945 context->pt_serv_buf_size - len);
946 len += strlen(wsi->u.hdr.stash->address);
947 net_num = htons((short)wsi->c_port);
948 /* the port we tell SOCKS proxy to connect to */
949 pt->serv_buf[len++] = net_buf[0];
950 pt->serv_buf[len++] = net_buf[1];
951 /* the length of the address, excluding port */
952 pt->serv_buf[len_index] = strlen(wsi->u.hdr.stash->address);