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);
29 if (wsi->vhost->http_proxy_port) {
30 plen = sprintf((char *)pt->serv_buf,
31 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
32 "User-agent: libwebsockets\x0d\x0a",
33 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
36 if (wsi->vhost->proxy_basic_auth_token[0])
37 plen += sprintf((char *)pt->serv_buf + plen,
38 "Proxy-authorization: basic %s\x0d\x0a",
39 wsi->vhost->proxy_basic_auth_token);
41 plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
42 ads = wsi->vhost->http_proxy_address;
45 if (LWS_IPV6_ENABLED(wsi->vhost)) {
46 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
47 server_addr6.sin6_port = htons(wsi->vhost->http_proxy_port);
50 server_addr4.sin_port = htons(wsi->vhost->http_proxy_port);
53 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
55 if (LWS_IPV6_ENABLED(wsi->vhost)) {
56 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
57 server_addr6.sin6_port = htons(wsi->c_port);
60 server_addr4.sin_port = htons(wsi->c_port);
64 * prepare the actual connection (to the proxy, if any)
66 lwsl_notice("%s: address %s\n", __func__, ads);
69 if (LWS_IPV6_ENABLED(wsi->vhost)) {
70 memset(&hints, 0, sizeof(struct addrinfo));
71 #if !defined(__ANDROID__)
72 hints.ai_family = AF_INET6;
73 hints.ai_flags = AI_V4MAPPED;
75 n = getaddrinfo(ads, NULL, &hints, &result);
78 lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
80 lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
82 cce = "getaddrinfo (ipv6) failed";
86 server_addr6.sin6_family = AF_INET6;
87 switch (result->ai_family) {
88 #if defined(__ANDROID__)
90 /* map IPv4 to IPv6 */
91 bzero((char *)&server_addr6.sin6_addr,
92 sizeof(struct in6_addr));
93 server_addr6.sin6_addr.s6_addr[10] = 0xff;
94 server_addr6.sin6_addr.s6_addr[11] = 0xff;
95 memcpy(&server_addr6.sin6_addr.s6_addr[12],
96 &((struct sockaddr_in *)result->ai_addr)->sin_addr,
97 sizeof(struct in_addr));
101 memcpy(&server_addr6.sin6_addr,
102 &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
103 sizeof(struct in6_addr));
106 lwsl_err("Unknown address family\n");
107 freeaddrinfo(result);
108 cce = "unknown address family";
112 freeaddrinfo(result);
116 struct addrinfo ai, *res, *result = NULL;
120 memset (&ai, 0, sizeof ai);
121 ai.ai_family = PF_UNSPEC;
122 ai.ai_socktype = SOCK_STREAM;
123 ai.ai_flags = AI_CANONNAME;
125 addr_rv = getaddrinfo(ads, NULL, &ai, &result);
129 switch (res->ai_family) {
131 p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
137 #if defined(LWS_FALLBACK_GETHOSTBYNAME)
138 } else if (addr_rv == EAI_SYSTEM) {
139 struct hostent *host;
141 lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
142 host = gethostbyname(ads);
146 lwsl_err("gethostbyname failed\n");
147 cce = "gethostbyname (ipv4) failed";
152 lwsl_err("getaddrinfo failed\n");
153 cce = "getaddrinfo (ipv4) failed";
159 freeaddrinfo(result);
160 lwsl_err("Couldn't identify address\n");
161 cce = "unable to lookup address";
165 server_addr4.sin_family = AF_INET;
166 server_addr4.sin_addr = *((struct in_addr *)p);
167 bzero(&server_addr4.sin_zero, 8);
169 freeaddrinfo(result);
172 if (!lws_socket_is_valid(wsi->desc.sockfd)) {
175 if (LWS_IPV6_ENABLED(wsi->vhost))
176 wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
179 wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
181 if (!lws_socket_is_valid(wsi->desc.sockfd)) {
182 lwsl_warn("Unable to open socket\n");
183 cce = "unable to open socket";
187 if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
188 lwsl_err("Failed to set wsi socket options\n");
189 compatible_close(wsi->desc.sockfd);
190 cce = "set socket opts failed";
194 wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
196 lws_libev_accept(wsi, wsi->desc);
197 lws_libuv_accept(wsi, wsi->desc);
198 lws_libevent_accept(wsi, wsi->desc);
199 if (insert_wsi_socket_into_fds(context, wsi)) {
200 compatible_close(wsi->desc.sockfd);
201 cce = "insert wsi failed";
205 lws_change_pollfd(wsi, 0, LWS_POLLIN);
208 * past here, we can't simply free the structs as error
209 * handling as oom4 does. We have to run the whole close flow.
213 wsi->protocol = &wsi->vhost->protocols[0];
215 wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
216 wsi->user_space, NULL, 0);
218 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
221 n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, wsi->vhost->iface);
223 cce = "unable to bind socket";
229 if (LWS_IPV6_ENABLED(wsi->vhost)) {
230 v = (struct sockaddr *)&server_addr6;
231 n = sizeof(struct sockaddr_in6);
235 v = (struct sockaddr *)&server_addr4;
236 n = sizeof(struct sockaddr);
239 if (connect(wsi->desc.sockfd, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
240 if (LWS_ERRNO == LWS_EALREADY ||
241 LWS_ERRNO == LWS_EINPROGRESS ||
242 LWS_ERRNO == LWS_EWOULDBLOCK
244 || LWS_ERRNO == WSAEINVAL
247 lwsl_client("nonblocking connect retry (errno = %d)\n",
250 if (lws_plat_check_connection_error(wsi)) {
251 cce = "socket connect failed";
256 * must do specifically a POLLOUT poll to hear
257 * about the connect completion
259 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
260 cce = "POLLOUT set failed";
267 if (LWS_ERRNO != LWS_EISCONN) {
268 lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
269 cce = "connect failed";
274 lwsl_client("connected\n");
276 /* we are connected to server, or proxy */
278 if (wsi->vhost->http_proxy_port) {
281 * OK from now on we talk via the proxy, so connect to that
283 * (will overwrite existing pointer,
284 * leaving old string/frag there but unreferenced)
286 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
287 wsi->vhost->http_proxy_address))
289 wsi->c_port = wsi->vhost->http_proxy_port;
291 n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
294 lwsl_debug("ERROR writing to proxy socket\n");
295 cce = "proxy write failed";
299 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
302 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
308 * provoke service to issue the handshake directly
309 * we need to do it this way because in the proxy case, this is the
310 * next state and executed only if and when we get a good proxy
311 * response inside the state machine... but notice in SSL case this
312 * may not have sent anything yet with 0 return, and won't until some
313 * many retries from main loop. To stop that becoming endless,
314 * cover with a timeout.
317 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
320 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
321 pfd.fd = wsi->desc.sockfd;
322 pfd.events = LWS_POLLIN;
323 pfd.revents = LWS_POLLIN;
325 n = lws_service_fd(context, &pfd);
327 cce = "first service failed";
330 if (n) /* returns 1 on failure after closing wsi */
336 /* we're closing, losing some rx is OK */
338 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
339 if (wsi->mode == LWSCM_HTTP_CLIENT ||
340 wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
341 wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
342 wsi->vhost->protocols[0].callback(wsi,
343 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
344 wsi->user_space, (void *)cce, strlen(cce));
345 wsi->already_did_cce = 1;
347 /* take care that we might be inserted in fds already */
348 if (wsi->position_in_fds_table != -1)
350 lws_remove_from_timeout_list(wsi);
351 lws_header_table_detach(wsi, 0);
357 wsi->vhost->protocols[0].callback(wsi,
358 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
359 wsi->user_space, (void *)cce, strlen(cce));
360 wsi->already_did_cce = 1;
362 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
368 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
369 * this only works if still in HTTP, ie, not upgraded yet
370 * wsi: connection to reset
371 * address: network address of the new server
372 * port: port to connect to
373 * path: uri path to connect to on the new server
374 * host: host header to send to the new server
376 LWS_VISIBLE struct lws *
377 lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
378 const char *path, const char *host)
380 char origin[300] = "", protocol[300] = "", method[32] = "", *p;
381 struct lws *wsi = *pwsi;
383 if (wsi->redirects == 3) {
384 lwsl_err("%s: Too many redirects\n", __func__);
389 #ifdef LWS_OPENSSL_SUPPORT
393 lwsl_err("%s: not configured for ssl\n", __func__);
398 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
400 strncpy(origin, p, sizeof(origin) - 1);
402 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
404 strncpy(protocol, p, sizeof(protocol) - 1);
406 p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
408 strncpy(method, p, sizeof(method) - 1);
410 lwsl_debug("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
411 address, port, path, ssl);
413 /* close the connection by hand */
415 compatible_close(wsi->desc.sockfd);
416 remove_wsi_socket_from_fds(wsi);
418 wsi->desc.sockfd = LWS_SOCK_INVALID;
419 wsi->state = LWSS_CLIENT_UNCONNECTED;
420 wsi->protocol = NULL;
421 wsi->pending_timeout = NO_PENDING_TIMEOUT;
423 wsi->hdr_parsing_completed = 0;
424 _lws_header_table_reset(wsi->u.hdr.ah);
426 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
429 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
433 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
437 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
441 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
446 strncpy(&origin[1], path, sizeof(origin) - 2);
447 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
450 *pwsi = lws_client_connect_2(wsi);
455 #ifdef LWS_WITH_HTTP_PROXY
457 html_parser_cb(const hubbub_token *token, void *pw)
459 struct lws_rewrite *r = (struct lws_rewrite *)pw;
460 char buf[1024], *start = buf + LWS_PRE, *p = start,
461 *end = &buf[sizeof(buf) - 1];
464 switch (token->type) {
465 case HUBBUB_TOKEN_DOCTYPE:
467 p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
468 (int) token->data.doctype.name.len,
469 token->data.doctype.name.ptr,
470 token->data.doctype.force_quirks ?
471 "(force-quirks) " : "");
473 if (token->data.doctype.public_missing)
474 printf("\tpublic: missing\n");
476 p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
477 (int) token->data.doctype.public_id.len,
478 token->data.doctype.public_id.ptr);
480 if (token->data.doctype.system_missing)
481 printf("\tsystem: missing\n");
483 p += lws_snprintf(p, end - p, " \"%.*s\">\n",
484 (int) token->data.doctype.system_id.len,
485 token->data.doctype.system_id.ptr);
488 case HUBBUB_TOKEN_START_TAG:
489 p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
490 token->data.tag.name.ptr);
492 /* (token->data.tag.self_closing) ?
493 "(self-closing) " : "",
494 (token->data.tag.n_attributes > 0) ?
497 for (i = 0; i < token->data.tag.n_attributes; i++) {
498 if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
499 !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
500 !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
501 const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
502 int plen = (int) token->data.tag.attributes[i].value.len;
504 if (!hstrcmp(&token->data.tag.attributes[i].value,
505 r->from, r->from_len)) {
509 p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
510 (int) token->data.tag.attributes[i].name.len,
511 token->data.tag.attributes[i].name.ptr,
516 p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
517 (int) token->data.tag.attributes[i].name.len,
518 token->data.tag.attributes[i].name.ptr,
519 (int) token->data.tag.attributes[i].value.len,
520 token->data.tag.attributes[i].value.ptr);
522 p += lws_snprintf(p, end - p, ">\n");
524 case HUBBUB_TOKEN_END_TAG:
525 p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
526 token->data.tag.name.ptr);
528 (token->data.tag.self_closing) ?
529 "(self-closing) " : "",
530 (token->data.tag.n_attributes > 0) ?
533 for (i = 0; i < token->data.tag.n_attributes; i++) {
534 p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
535 (int) token->data.tag.attributes[i].name.len,
536 token->data.tag.attributes[i].name.ptr,
537 (int) token->data.tag.attributes[i].value.len,
538 token->data.tag.attributes[i].value.ptr);
540 p += lws_snprintf(p, end - p, ">\n");
542 case HUBBUB_TOKEN_COMMENT:
543 p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
544 (int) token->data.comment.len,
545 token->data.comment.ptr);
547 case HUBBUB_TOKEN_CHARACTER:
548 p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
549 token->data.character.ptr);
551 case HUBBUB_TOKEN_EOF:
552 p += lws_snprintf(p, end - p, "\n");
556 if (user_callback_handle_rxflow(r->wsi->protocol->callback,
557 r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
558 r->wsi->user_space, start, p - start))
565 LWS_VISIBLE struct lws *
566 lws_client_connect_via_info(struct lws_client_connect_info *i)
569 int v = SPEC_LATEST_SUPPORTED;
570 const struct lws_protocols *p;
572 if (i->context->requested_kill)
575 if (!i->context->protocol_init_done)
576 lws_protocol_init(i->context);
578 wsi = lws_zalloc(sizeof(struct lws));
582 wsi->context = i->context;
583 /* assert the mode and union status (hdr) clearly */
584 lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
585 wsi->desc.sockfd = LWS_SOCK_INVALID;
587 /* 1) fill up the wsi with stuff from the connect_info as far as it
588 * can go. It's because not only is our connection async, we might
589 * not even be able to get ahold of an ah at this point.
592 /* -1 means just use latest supported */
593 if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
594 v = i->ietf_version_or_minus_one;
596 wsi->ietf_spec_revision = v;
597 wsi->user_space = NULL;
598 wsi->state = LWSS_CLIENT_UNCONNECTED;
599 wsi->pending_timeout = NO_PENDING_TIMEOUT;
600 wsi->position_in_fds_table = -1;
601 wsi->c_port = i->port;
602 wsi->vhost = i->vhost;
604 wsi->vhost = i->context->vhost_list;
606 wsi->protocol = &wsi->vhost->protocols[0];
608 /* for http[s] connection, allow protocol selection by name */
610 if (i->method && i->vhost && i->protocol) {
611 p = lws_vhost_name_to_protocol(i->vhost, i->protocol);
616 if (wsi && !wsi->user_space && i->userdata) {
617 wsi->user_space_externally_allocated = 1;
618 wsi->user_space = i->userdata;
620 /* if we stay in http, we can assign the user space now,
621 * otherwise do it after the protocol negotiated
624 if (lws_ensure_user_space(wsi))
627 #ifdef LWS_OPENSSL_SUPPORT
628 wsi->use_ssl = i->ssl_connection;
630 if (i->ssl_connection) {
631 lwsl_err("libwebsockets not configured for ssl\n");
636 /* 2) stash the things from connect_info that we can't process without
637 * an ah. Because if no ah, we will go on the ah waiting list and
638 * process those things later (after the connect_info and maybe the
639 * things pointed to have gone out of scope.
642 wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
643 if (!wsi->u.hdr.stash) {
644 lwsl_err("%s: OOM\n", __func__);
648 wsi->u.hdr.stash->origin[0] = '\0';
649 wsi->u.hdr.stash->protocol[0] = '\0';
650 wsi->u.hdr.stash->method[0] = '\0';
652 strncpy(wsi->u.hdr.stash->address, i->address,
653 sizeof(wsi->u.hdr.stash->address) - 1);
654 strncpy(wsi->u.hdr.stash->path, i->path,
655 sizeof(wsi->u.hdr.stash->path) - 1);
656 strncpy(wsi->u.hdr.stash->host, i->host,
657 sizeof(wsi->u.hdr.stash->host) - 1);
659 strncpy(wsi->u.hdr.stash->origin, i->origin,
660 sizeof(wsi->u.hdr.stash->origin) - 1);
662 strncpy(wsi->u.hdr.stash->protocol, i->protocol,
663 sizeof(wsi->u.hdr.stash->protocol) - 1);
665 strncpy(wsi->u.hdr.stash->method, i->method,
666 sizeof(wsi->u.hdr.stash->method) - 1);
668 wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
669 wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
670 wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
671 wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
672 wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
673 wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
678 /* if we went on the waiting list, no probs just return the wsi
679 * when we get the ah, now or later, he will call
680 * lws_client_connect_via_info2() below.
682 if (lws_header_table_attach(wsi, 0) < 0) {
684 * if we failed here, the connection is already closed
691 lwsl_info("%s: created child %p of parent %p\n", __func__,
693 wsi->parent = i->parent_wsi;
694 wsi->sibling_list = i->parent_wsi->child_list;
695 i->parent_wsi->child_list = wsi;
697 #ifdef LWS_WITH_HTTP_PROXY
698 if (i->uri_replace_to)
699 wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
717 lws_client_connect_via_info2(struct lws *wsi)
719 struct client_info_stash *stash = wsi->u.hdr.stash;
725 * we're not necessarily in a position to action these right away,
726 * stash them... we only need during connect phase so u.hdr is fine
728 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
732 /* these only need u.hdr lifetime as well */
734 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
737 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
740 if (stash->origin[0])
741 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
745 * this is a list of protocols we tell the server we're okay with
746 * stash it for later when we compare server response with it
748 if (stash->protocol[0])
749 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
752 if (stash->method[0])
753 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
757 lws_free_set_NULL(wsi->u.hdr.stash);
760 * Check with each extension if it is able to route and proxy this
761 * connection for us. For example, an extension like x-google-mux
762 * can handle this and then we don't need an actual socket for this
766 if (lws_ext_cb_all_exts(wsi->context, wsi,
767 LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
768 (void *)stash->address,
770 lwsl_client("lws_client_connect: ext handling conn\n");
773 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
776 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
779 lwsl_client("lws_client_connect: direct conn\n");
780 wsi->context->count_wsi_allocated++;
782 return lws_client_connect_2(wsi);
785 lws_free_set_NULL(wsi->u.hdr.stash);
790 LWS_VISIBLE struct lws *
791 lws_client_connect_extended(struct lws_context *context, const char *address,
792 int port, int ssl_connection, const char *path,
793 const char *host, const char *origin,
794 const char *protocol, int ietf_version_or_minus_one,
797 struct lws_client_connect_info i;
799 memset(&i, 0, sizeof(i));
804 i.ssl_connection = ssl_connection;
808 i.protocol = protocol;
809 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
810 i.userdata = userdata;
812 return lws_client_connect_via_info(&i);
815 LWS_VISIBLE struct lws *
816 lws_client_connect(struct lws_context *context, const char *address,
817 int port, int ssl_connection, const char *path,
818 const char *host, const char *origin,
819 const char *protocol, int ietf_version_or_minus_one)
821 struct lws_client_connect_info i;
823 memset(&i, 0, sizeof(i));
828 i.ssl_connection = ssl_connection;
832 i.protocol = protocol;
833 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
836 return lws_client_connect_via_info(&i);