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));
126 lwsl_err("Unknown address family\n");
127 freeaddrinfo(result);
128 cce = "unknown address family";
132 freeaddrinfo(result);
136 struct addrinfo ai, *res, *result = NULL;
140 memset (&ai, 0, sizeof ai);
141 ai.ai_family = PF_UNSPEC;
142 ai.ai_socktype = SOCK_STREAM;
143 ai.ai_flags = AI_CANONNAME;
145 addr_rv = getaddrinfo(ads, NULL, &ai, &result);
149 switch (res->ai_family) {
151 p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
157 #if defined(LWS_FALLBACK_GETHOSTBYNAME)
158 } else if (addr_rv == EAI_SYSTEM) {
159 struct hostent *host;
161 lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
162 host = gethostbyname(ads);
166 lwsl_err("gethostbyname failed\n");
167 cce = "gethostbyname (ipv4) failed";
172 lwsl_err("getaddrinfo failed\n");
173 cce = "getaddrinfo (ipv4) failed";
179 freeaddrinfo(result);
180 lwsl_err("Couldn't identify address\n");
181 cce = "unable to lookup address";
185 server_addr4.sin_family = AF_INET;
186 server_addr4.sin_addr = *((struct in_addr *)p);
187 bzero(&server_addr4.sin_zero, 8);
189 freeaddrinfo(result);
192 if (!lws_socket_is_valid(wsi->desc.sockfd)) {
195 if (LWS_IPV6_ENABLED(wsi->vhost))
196 wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
199 wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
201 if (!lws_socket_is_valid(wsi->desc.sockfd)) {
202 lwsl_warn("Unable to open socket\n");
203 cce = "unable to open socket";
207 if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
208 lwsl_err("Failed to set wsi socket options\n");
209 compatible_close(wsi->desc.sockfd);
210 cce = "set socket opts failed";
214 wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
216 lws_libev_accept(wsi, wsi->desc);
217 lws_libuv_accept(wsi, wsi->desc);
218 lws_libevent_accept(wsi, wsi->desc);
219 if (insert_wsi_socket_into_fds(context, wsi)) {
220 compatible_close(wsi->desc.sockfd);
221 cce = "insert wsi failed";
225 lws_change_pollfd(wsi, 0, LWS_POLLIN);
228 * past here, we can't simply free the structs as error
229 * handling as oom4 does. We have to run the whole close flow.
233 wsi->protocol = &wsi->vhost->protocols[0];
235 wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
236 wsi->user_space, NULL, 0);
238 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
241 n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, wsi->vhost->iface);
243 cce = "unable to bind socket";
249 if (LWS_IPV6_ENABLED(wsi->vhost)) {
250 v = (struct sockaddr *)&server_addr6;
251 n = sizeof(struct sockaddr_in6);
255 v = (struct sockaddr *)&server_addr4;
256 n = sizeof(struct sockaddr);
259 if (connect(wsi->desc.sockfd, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
260 if (LWS_ERRNO == LWS_EALREADY ||
261 LWS_ERRNO == LWS_EINPROGRESS ||
262 LWS_ERRNO == LWS_EWOULDBLOCK
264 || LWS_ERRNO == WSAEINVAL
267 lwsl_client("nonblocking connect retry (errno = %d)\n",
270 if (lws_plat_check_connection_error(wsi)) {
271 cce = "socket connect failed";
276 * must do specifically a POLLOUT poll to hear
277 * about the connect completion
279 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
280 cce = "POLLOUT set failed";
287 if (LWS_ERRNO != LWS_EISCONN) {
288 lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
289 cce = "connect failed";
294 lwsl_client("connected\n");
296 /* we are connected to server, or proxy */
299 if (wsi->vhost->http_proxy_port) {
302 * OK from now on we talk via the proxy, so connect to that
304 * (will overwrite existing pointer,
305 * leaving old string/frag there but unreferenced)
307 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
308 wsi->vhost->http_proxy_address))
310 wsi->c_port = wsi->vhost->http_proxy_port;
312 n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
315 lwsl_debug("ERROR writing to proxy socket\n");
316 cce = "proxy write failed";
320 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
323 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
327 #if defined(LWS_WITH_SOCKS5)
329 else if (wsi->vhost->socks_proxy_port) {
330 n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
333 lwsl_debug("ERROR writing greeting to socks proxy"
335 cce = "socks write failed";
339 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
342 wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;
349 * provoke service to issue the handshake directly
350 * we need to do it this way because in the proxy case, this is the
351 * next state and executed only if and when we get a good proxy
352 * response inside the state machine... but notice in SSL case this
353 * may not have sent anything yet with 0 return, and won't until some
354 * many retries from main loop. To stop that becoming endless,
355 * cover with a timeout.
358 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
361 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
362 pfd.fd = wsi->desc.sockfd;
363 pfd.events = LWS_POLLIN;
364 pfd.revents = LWS_POLLIN;
366 n = lws_service_fd(context, &pfd);
368 cce = "first service failed";
371 if (n) /* returns 1 on failure after closing wsi */
377 /* we're closing, losing some rx is OK */
379 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
380 if (wsi->mode == LWSCM_HTTP_CLIENT ||
381 wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
382 wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
383 wsi->vhost->protocols[0].callback(wsi,
384 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
385 wsi->user_space, (void *)cce, strlen(cce));
386 wsi->already_did_cce = 1;
388 /* take care that we might be inserted in fds already */
389 if (wsi->position_in_fds_table != -1)
391 lws_remove_from_timeout_list(wsi);
392 lws_header_table_detach(wsi, 0);
398 wsi->vhost->protocols[0].callback(wsi,
399 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
400 wsi->user_space, (void *)cce, strlen(cce));
401 wsi->already_did_cce = 1;
403 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
409 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
410 * this only works if still in HTTP, ie, not upgraded yet
411 * wsi: connection to reset
412 * address: network address of the new server
413 * port: port to connect to
414 * path: uri path to connect to on the new server
415 * host: host header to send to the new server
417 LWS_VISIBLE struct lws *
418 lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
419 const char *path, const char *host)
421 char origin[300] = "", protocol[300] = "", method[32] = "", *p;
422 struct lws *wsi = *pwsi;
424 if (wsi->redirects == 3) {
425 lwsl_err("%s: Too many redirects\n", __func__);
430 #ifdef LWS_OPENSSL_SUPPORT
434 lwsl_err("%s: not configured for ssl\n", __func__);
439 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
441 strncpy(origin, p, sizeof(origin) - 1);
443 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
445 strncpy(protocol, p, sizeof(protocol) - 1);
447 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
449 strncpy(method, p, sizeof(method) - 1);
451 lwsl_debug("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
452 address, port, path, ssl);
454 /* close the connection by hand */
456 compatible_close(wsi->desc.sockfd);
457 remove_wsi_socket_from_fds(wsi);
459 wsi->desc.sockfd = LWS_SOCK_INVALID;
460 wsi->state = LWSS_CLIENT_UNCONNECTED;
461 wsi->protocol = NULL;
462 wsi->pending_timeout = NO_PENDING_TIMEOUT;
464 wsi->hdr_parsing_completed = 0;
465 _lws_header_table_reset(wsi->u.hdr.ah);
467 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
470 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
474 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
478 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
482 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
487 strncpy(&origin[1], path, sizeof(origin) - 2);
488 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
491 *pwsi = lws_client_connect_2(wsi);
496 #ifdef LWS_WITH_HTTP_PROXY
498 html_parser_cb(const hubbub_token *token, void *pw)
500 struct lws_rewrite *r = (struct lws_rewrite *)pw;
501 char buf[1024], *start = buf + LWS_PRE, *p = start,
502 *end = &buf[sizeof(buf) - 1];
505 switch (token->type) {
506 case HUBBUB_TOKEN_DOCTYPE:
508 p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
509 (int) token->data.doctype.name.len,
510 token->data.doctype.name.ptr,
511 token->data.doctype.force_quirks ?
512 "(force-quirks) " : "");
514 if (token->data.doctype.public_missing)
515 printf("\tpublic: missing\n");
517 p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
518 (int) token->data.doctype.public_id.len,
519 token->data.doctype.public_id.ptr);
521 if (token->data.doctype.system_missing)
522 printf("\tsystem: missing\n");
524 p += lws_snprintf(p, end - p, " \"%.*s\">\n",
525 (int) token->data.doctype.system_id.len,
526 token->data.doctype.system_id.ptr);
529 case HUBBUB_TOKEN_START_TAG:
530 p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
531 token->data.tag.name.ptr);
533 /* (token->data.tag.self_closing) ?
534 "(self-closing) " : "",
535 (token->data.tag.n_attributes > 0) ?
538 for (i = 0; i < token->data.tag.n_attributes; i++) {
539 if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
540 !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
541 !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
542 const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
543 int plen = (int) token->data.tag.attributes[i].value.len;
545 if (!hstrcmp(&token->data.tag.attributes[i].value,
546 r->from, r->from_len)) {
550 p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
551 (int) token->data.tag.attributes[i].name.len,
552 token->data.tag.attributes[i].name.ptr,
557 p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
558 (int) token->data.tag.attributes[i].name.len,
559 token->data.tag.attributes[i].name.ptr,
560 (int) token->data.tag.attributes[i].value.len,
561 token->data.tag.attributes[i].value.ptr);
563 p += lws_snprintf(p, end - p, ">\n");
565 case HUBBUB_TOKEN_END_TAG:
566 p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
567 token->data.tag.name.ptr);
569 (token->data.tag.self_closing) ?
570 "(self-closing) " : "",
571 (token->data.tag.n_attributes > 0) ?
574 for (i = 0; i < token->data.tag.n_attributes; i++) {
575 p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
576 (int) token->data.tag.attributes[i].name.len,
577 token->data.tag.attributes[i].name.ptr,
578 (int) token->data.tag.attributes[i].value.len,
579 token->data.tag.attributes[i].value.ptr);
581 p += lws_snprintf(p, end - p, ">\n");
583 case HUBBUB_TOKEN_COMMENT:
584 p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
585 (int) token->data.comment.len,
586 token->data.comment.ptr);
588 case HUBBUB_TOKEN_CHARACTER:
589 p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
590 token->data.character.ptr);
592 case HUBBUB_TOKEN_EOF:
593 p += lws_snprintf(p, end - p, "\n");
597 if (user_callback_handle_rxflow(r->wsi->protocol->callback,
598 r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
599 r->wsi->user_space, start, p - start))
606 LWS_VISIBLE struct lws *
607 lws_client_connect_via_info(struct lws_client_connect_info *i)
610 int v = SPEC_LATEST_SUPPORTED;
611 const struct lws_protocols *p;
613 if (i->context->requested_kill)
616 if (!i->context->protocol_init_done)
617 lws_protocol_init(i->context);
619 wsi = lws_zalloc(sizeof(struct lws));
623 wsi->context = i->context;
624 /* assert the mode and union status (hdr) clearly */
625 lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
626 wsi->desc.sockfd = LWS_SOCK_INVALID;
628 /* 1) fill up the wsi with stuff from the connect_info as far as it
629 * can go. It's because not only is our connection async, we might
630 * not even be able to get ahold of an ah at this point.
633 /* -1 means just use latest supported */
634 if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
635 v = i->ietf_version_or_minus_one;
637 wsi->ietf_spec_revision = v;
638 wsi->user_space = NULL;
639 wsi->state = LWSS_CLIENT_UNCONNECTED;
640 wsi->pending_timeout = NO_PENDING_TIMEOUT;
641 wsi->position_in_fds_table = -1;
642 wsi->c_port = i->port;
643 wsi->vhost = i->vhost;
645 wsi->vhost = i->context->vhost_list;
647 wsi->protocol = &wsi->vhost->protocols[0];
649 /* for http[s] connection, allow protocol selection by name */
651 if (i->method && i->vhost && i->protocol) {
652 p = lws_vhost_name_to_protocol(i->vhost, i->protocol);
657 if (wsi && !wsi->user_space && i->userdata) {
658 wsi->user_space_externally_allocated = 1;
659 wsi->user_space = i->userdata;
661 /* if we stay in http, we can assign the user space now,
662 * otherwise do it after the protocol negotiated
665 if (lws_ensure_user_space(wsi))
668 #ifdef LWS_OPENSSL_SUPPORT
669 wsi->use_ssl = i->ssl_connection;
671 if (i->ssl_connection) {
672 lwsl_err("libwebsockets not configured for ssl\n");
677 /* 2) stash the things from connect_info that we can't process without
678 * an ah. Because if no ah, we will go on the ah waiting list and
679 * process those things later (after the connect_info and maybe the
680 * things pointed to have gone out of scope.
683 wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
684 if (!wsi->u.hdr.stash) {
685 lwsl_err("%s: OOM\n", __func__);
689 wsi->u.hdr.stash->origin[0] = '\0';
690 wsi->u.hdr.stash->protocol[0] = '\0';
691 wsi->u.hdr.stash->method[0] = '\0';
693 strncpy(wsi->u.hdr.stash->address, i->address,
694 sizeof(wsi->u.hdr.stash->address) - 1);
695 strncpy(wsi->u.hdr.stash->path, i->path,
696 sizeof(wsi->u.hdr.stash->path) - 1);
697 strncpy(wsi->u.hdr.stash->host, i->host,
698 sizeof(wsi->u.hdr.stash->host) - 1);
700 strncpy(wsi->u.hdr.stash->origin, i->origin,
701 sizeof(wsi->u.hdr.stash->origin) - 1);
703 strncpy(wsi->u.hdr.stash->protocol, i->protocol,
704 sizeof(wsi->u.hdr.stash->protocol) - 1);
706 strncpy(wsi->u.hdr.stash->method, i->method,
707 sizeof(wsi->u.hdr.stash->method) - 1);
709 wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
710 wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
711 wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
712 wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
713 wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
714 wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
719 /* if we went on the waiting list, no probs just return the wsi
720 * when we get the ah, now or later, he will call
721 * lws_client_connect_via_info2() below.
723 if (lws_header_table_attach(wsi, 0) < 0) {
725 * if we failed here, the connection is already closed
732 lwsl_info("%s: created child %p of parent %p\n", __func__,
734 wsi->parent = i->parent_wsi;
735 wsi->sibling_list = i->parent_wsi->child_list;
736 i->parent_wsi->child_list = wsi;
738 #ifdef LWS_WITH_HTTP_PROXY
739 if (i->uri_replace_to)
740 wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
758 lws_client_connect_via_info2(struct lws *wsi)
760 struct client_info_stash *stash = wsi->u.hdr.stash;
766 * we're not necessarily in a position to action these right away,
767 * stash them... we only need during connect phase so u.hdr is fine
769 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
773 /* these only need u.hdr lifetime as well */
775 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
778 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
781 if (stash->origin[0])
782 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
786 * this is a list of protocols we tell the server we're okay with
787 * stash it for later when we compare server response with it
789 if (stash->protocol[0])
790 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
793 if (stash->method[0])
794 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
798 #if defined(LWS_WITH_SOCKS5)
799 if (!wsi->vhost->socks_proxy_port)
800 lws_free_set_NULL(wsi->u.hdr.stash);
804 * Check with each extension if it is able to route and proxy this
805 * connection for us. For example, an extension like x-google-mux
806 * can handle this and then we don't need an actual socket for this
810 if (lws_ext_cb_all_exts(wsi->context, wsi,
811 LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
812 (void *)stash->address,
814 lwsl_client("lws_client_connect: ext handling conn\n");
817 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
820 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
823 lwsl_client("lws_client_connect: direct conn\n");
824 wsi->context->count_wsi_allocated++;
826 return lws_client_connect_2(wsi);
829 #if defined(LWS_WITH_SOCKS5)
830 if (!wsi->vhost->socks_proxy_port)
831 lws_free_set_NULL(wsi->u.hdr.stash);
837 LWS_VISIBLE struct lws *
838 lws_client_connect_extended(struct lws_context *context, const char *address,
839 int port, int ssl_connection, const char *path,
840 const char *host, const char *origin,
841 const char *protocol, int ietf_version_or_minus_one,
844 struct lws_client_connect_info i;
846 memset(&i, 0, sizeof(i));
851 i.ssl_connection = ssl_connection;
855 i.protocol = protocol;
856 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
857 i.userdata = userdata;
859 return lws_client_connect_via_info(&i);
862 LWS_VISIBLE struct lws *
863 lws_client_connect(struct lws_context *context, const char *address,
864 int port, int ssl_connection, const char *path,
865 const char *host, const char *origin,
866 const char *protocol, int ietf_version_or_minus_one)
868 struct lws_client_connect_info i;
870 memset(&i, 0, sizeof(i));
875 i.ssl_connection = ssl_connection;
879 i.protocol = protocol;
880 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
883 return lws_client_connect_via_info(&i);
886 #if defined(LWS_WITH_SOCKS5)
887 void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
890 struct lws_context *context = wsi->context;
891 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
894 if (type == SOCKS_MSG_GREETING) {
895 /* socks version, version 5 only */
896 pt->serv_buf[len++] = SOCKS_VERSION_5;
897 /* number of methods */
898 pt->serv_buf[len++] = 2;
899 /* username password method */
900 pt->serv_buf[len++] = SOCKS_AUTH_USERNAME_PASSWORD;
901 /* no authentication method */
902 pt->serv_buf[len++] = SOCKS_AUTH_NO_AUTH;
904 else if (type == SOCKS_MSG_USERNAME_PASSWORD) {
906 size_t passwd_len = 0;
908 user_len = strlen(wsi->vhost->socks_user);
909 passwd_len = strlen(wsi->vhost->socks_password);
911 /* the subnegotiation version */
912 pt->serv_buf[len++] = SOCKS_SUBNEGOTIATION_VERSION_1;
913 /* length of the user name */
914 pt->serv_buf[len++] = user_len;
916 strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_user,
917 context->pt_serv_buf_size - len);
919 /* length of the password */
920 pt->serv_buf[len++] = passwd_len;
922 strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_password,
923 context->pt_serv_buf_size - len);
926 else if (type == SOCKS_MSG_CONNECT) {
927 size_t len_index = 0;
929 char *net_buf = (char*)&net_num;
932 pt->serv_buf[len++] = SOCKS_VERSION_5;
934 pt->serv_buf[len++] = SOCKS_COMMAND_CONNECT;
936 pt->serv_buf[len++] = 0;
938 pt->serv_buf[len++] = SOCKS_ATYP_DOMAINNAME;
941 /* the address we tell SOCKS proxy to connect to */
942 strncpy((char *)&(pt->serv_buf[len]), wsi->u.hdr.stash->address,
943 context->pt_serv_buf_size - len);
944 len += strlen(wsi->u.hdr.stash->address);
945 net_num = htons((short)wsi->c_port);
946 /* the port we tell SOCKS proxy to connect to */
947 pt->serv_buf[len++] = net_buf[0];
948 pt->serv_buf[len++] = net_buf[1];
949 /* the length of the address, excluding port */
950 pt->serv_buf[len_index] = strlen(wsi->u.hdr.stash->address);