Newer
Older
static int
lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
*result = NULL;
if (wsi->ipv6) {
#if !defined(__ANDROID__)
hints.ai_family = AF_INET6;
hints.ai_flags = AI_V4MAPPED;
#endif
} else
{
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
}
return getaddrinfo(ads, NULL, &hints, result);
}
struct lws *
lws_client_connect_2(struct lws *wsi)
{
struct lws_context *context = wsi->context;
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
const char *cce = "", *iface, *adsin, *meth;
struct lws *wsi_piggy = NULL;
struct addrinfo *result;
char ipv6only = lws_check_opt(wsi->vhost->options,
LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
#if defined(__ANDROID__)
ipv6only = 0;
#endif
#endif
lwsl_client("%s\n", __func__);
cce = "ah was NULL at cc2";
lwsl_err("%s\n", cce);
goto oom4;
}
/* we can only piggyback GET */
meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
if (meth && strcmp(meth, "GET"))
goto create_new_conn;
/* we only pipeline connections that said it was okay */
if (!wsi->client_pipeline)
goto create_new_conn;
/*
* let's take a look first and see if there are any already-active
* client connections we can piggy-back on.
*/
adsin = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
lws_vhost_lock(wsi->vhost);
lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
wsi->vhost->dll_active_client_conns.next) {
struct lws *w = lws_container_of(d, struct lws,
dll_active_client_conns);
if (w->client_hostname_copy &&
!strcmp(adsin, w->client_hostname_copy) &&
#ifdef LWS_OPENSSL_SUPPORT
(wsi->use_ssl & (LCCSCF_NOT_H2 | LCCSCF_USE_SSL)) ==
(w->use_ssl & (LCCSCF_NOT_H2 | LCCSCF_USE_SSL)) &&
#endif
/* someone else is already connected to the right guy */
/* do we know for a fact pipelining won't fly? */
if (w->keepalive_rejected) {
#if defined (LWS_WITH_HTTP2)
/*
* h2: in usable state already: just use it without
* going through the queue
*/
if (w->client_h2_alpn &&
(w->state == LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS ||
w->state == LWSS_HTTP2_CLIENT_ESTABLISHED)) {
lwsl_info("%s: just join h2 directly\n",
__func__);
lws_wsi_h2_adopt(w, wsi);
lws_vhost_unlock(wsi->vhost);
return wsi;
}
#endif
lwsl_info("applying %p to txn queue on %p (%d)\n", wsi, w,
w->state);
/*
* ...let's add ourselves to his transaction queue...
*/
lws_dll_lws_add_front(&wsi->dll_client_transaction_queue,
&w->dll_client_transaction_queue_head);
* h1: pipeline our headers out on him,
* and wait for our turn at client transaction_complete
* to take over parsing the rx.
*/
wsi_piggy = w;
lws_vhost_unlock(wsi->vhost);
goto send_hs;
}
} lws_end_foreach_dll_safe(d, d1);
lws_vhost_unlock(wsi->vhost);
create_new_conn:
/*
* clients who will create their own fresh connection keep a copy of
* the hostname they originally connected to, in case other connections
* want to use it too
*/
if (!wsi->client_hostname_copy)
wsi->client_hostname_copy =
strdup(lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_PEER_ADDRESS));
/*
* start off allowing ipv6 on connection if vhost allows it
*/
wsi->ipv6 = LWS_IPV6_ENABLED(wsi->vhost);
/* Decide what it is we need to connect to:
*
* Priority 1: connect to http proxy */
"CONNECT %s:%u HTTP/1.0\x0d\x0a"
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
/* Priority 2: Connect to SOCK5 Proxy */
} else if (wsi->vhost->socks_proxy_port) {
socks_generate_msg(wsi, SOCKS_MSG_GREETING, &plen);
} else {
/* Priority 3: Connect directly */
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
* prepare the actual connection
* to whatever we decided to connect to
lwsl_info("%s: %p: address %s\n", __func__, wsi, ads);
struct sockaddr_in6 *sa6 =
((struct sockaddr_in6 *)result->ai_addr);
if (n) {
/* lws_getaddrinfo46 failed, there is no usable result */
lwsl_notice("%s: lws_getaddrinfo46 failed %d\n",
__func__, n);
cce = "ipv6 lws_getaddrinfo46 failed";
goto oom4;
}
memset(&sa46, 0, sizeof(sa46));
sa46.sa6.sin6_family = AF_INET6;
case AF_INET:
/* map IPv4 to IPv6 */
bzero((char *)&sa46.sa6.sin6_addr,
sizeof(sa46.sa6.sin6_addr));
sa46.sa6.sin6_addr.s6_addr[10] = 0xff;
sa46.sa6.sin6_addr.s6_addr[11] = 0xff;
memcpy(&sa46.sa6.sin6_addr.s6_addr[12],
&((struct sockaddr_in *)result->ai_addr)->sin_addr,
sizeof(struct in_addr));
lwsl_notice("uplevelling AF_INET to AF_INET6\n");
sa46.sa6.sin6_scope_id = sa6->sin6_scope_id;
sa46.sa6.sin6_flowinfo = sa6->sin6_flowinfo;
break;
default:
lwsl_err("Unknown address family\n");
freeaddrinfo(result);
if (!n) {
struct addrinfo *res = result;
/* pick the first AF_INET (IPv4) result */
while (!p && res) {
switch (res->ai_family) {
case AF_INET:
p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
break;
}
res = res->ai_next;
}
#if defined(LWS_FALLBACK_GETHOSTBYNAME)
struct hostent *host;
lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
host = gethostbyname(ads);
if (host) {
p = host->h_addr;
} else {
lwsl_err("gethostbyname failed\n");
cce = "gethostbyname (ipv4) failed";
goto oom4;
}
#endif
} else {
lwsl_err("Couldn't identify address\n");
sa46.sa4.sin_family = AF_INET;
sa46.sa4.sin_addr = *((struct in_addr *)p);
bzero(&sa46.sa4.sin_zero, 8);
if (result)
freeaddrinfo(result);
/* now we decided on ipv4 or ipv6, set the port */
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
if (LWS_LIBUV_ENABLED(context))
if (lws_libuv_check_watcher_active(wsi)) {
lwsl_warn("Waiting for libuv watcher to close\n");
cce = "waiting for libuv watcher to close";
goto oom4;
}
#endif
wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
lwsl_warn("Unable to open socket\n");
if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
lwsl_err("Failed to set wsi socket options\n");
compatible_close(wsi->desc.sockfd);
lws_libev_accept(wsi, wsi->desc);
lws_libuv_accept(wsi, wsi->desc);
lws_libevent_accept(wsi, wsi->desc);
compatible_close(wsi->desc.sockfd);
/*
* past here, we can't simply free the structs as error
* handling as oom4 does. We have to run the whole close flow.
*/
if (!wsi->protocol)
wsi->protocol = &wsi->vhost->protocols[0];
wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
wsi->user_space, NULL, 0);
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
if (iface) {
n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, iface);
if (n < 0) {
cce = "unable to bind socket";
goto failed;
}
if (wsi->ipv6) {
sa46.sa6.sin6_port = htons(port);
{
sa46.sa4.sin_port = htons(port);
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
if (LWS_ERRNO == LWS_EALREADY ||
LWS_ERRNO == LWS_EINPROGRESS ||
LWS_ERRNO == LWS_EWOULDBLOCK
#ifdef _WIN32
|| LWS_ERRNO == WSAEINVAL
#endif
lwsl_client("nonblocking connect retry (errno = %d)\n",
LWS_ERRNO);
if (lws_plat_check_connection_error(wsi)) {
cce = "socket connect failed";
/*
* must do specifically a POLLOUT poll to hear
* about the connect completion
*/
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
cce = "POLLOUT set failed";
if (LWS_ERRNO != LWS_EISCONN) {
lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
cce = "connect failed";
goto failed;
}
/* we are connected to server, or proxy */
* OK from now on we talk via the proxy, so connect to that
*
* (will overwrite existing pointer,
* leaving old string/frag there but unreferenced)
*/
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
wsi->c_port = wsi->vhost->http_proxy_port;
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, (int)plen,
lwsl_debug("ERROR writing to proxy socket\n");
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
AWAITING_TIMEOUT);
#if defined(LWS_WITH_SOCKS5)
/* socks proxy */
else if (wsi->vhost->socks_proxy_port) {
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
MSG_NOSIGNAL);
if (n < 0) {
lwsl_debug("ERROR writing socks greeting\n");
cce = "socks write failed";
goto failed;
}
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
AWAITING_TIMEOUT);
wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;
return wsi;
}
#endif
if (wsi_piggy &&
!lws_dll_is_null(&wsi->dll_client_transaction_queue)) {
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
/*
* We are pipelining on an already-established connection...
* we can skip tls establishment.
*/
wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE2;
/*
* we can't send our headers directly, because they have to
* be sent when the parent is writeable. The parent will check
* for anybody on his client transaction queue that is in
* LWSCM_WSCL_ISSUE_HANDSHAKE2, and let them write.
*
* If we are trying to do this too early, before the master
* connection has written his own headers,
*/
lws_callback_on_writable(wsi_piggy);
lwsl_debug("wsi %p: waiting to send headers\n", wsi);
} else {
/* we are making our own connection */
wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
/*
* provoke service to issue the handshake directly.
*
* we need to do it this way because in the proxy case, this is
* the next state and executed only if and when we get a good
* proxy response inside the state machine... but notice in
* SSL case this may not have sent anything yet with 0 return,
* and won't until many retries from main loop. To stop that
* becoming endless, cover with a timeout.
*/
lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
AWAITING_TIMEOUT);
pfd.fd = wsi->desc.sockfd;
pfd.events = LWS_POLLIN;
pfd.revents = LWS_POLLIN;
n = lws_service_fd(context, &pfd);
if (n < 0) {
cce = "first service failed";
goto failed;
}
if (n) /* returns 1 on failure after closing wsi */
return NULL;
}
/*
* If we made our own connection, and we're doing a method that can take
* a pipeline, we are an "active client connection".
*
* Add ourselves to the vhost list of those so that others can
* piggyback on our transaction queue
*/
if (meth && !strcmp(meth, "GET") &&
lws_dll_is_null(&wsi->dll_client_transaction_queue)) {
lws_vhost_lock(wsi->vhost);
lws_dll_lws_add_front(&wsi->dll_active_client_conns,
&wsi->vhost->dll_active_client_conns);
lws_vhost_unlock(wsi->vhost);
lws_header_table_force_to_detachable_state(wsi);
wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
wsi->protocol->callback(wsi,
wsi->user_space, (void *)cce, strlen(cce));
wsi->already_did_cce = 1;
}
/* take care that we might be inserted in fds already */
if (wsi->position_in_fds_table != -1)
lws_remove_from_timeout_list(wsi);
wsi->protocol->callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, (void *)cce, strlen(cce));
wsi->already_did_cce = 1;
failed1:
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
/**
* lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
* this only works if still in HTTP, ie, not upgraded yet
* wsi: connection to reset
* address: network address of the new server
* port: port to connect to
* path: uri path to connect to on the new server
* host: host header to send to the new server
*/
LWS_VISIBLE struct lws *
lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
const char *path, const char *host)
char origin[300] = "", protocol[300] = "", method[32] = "",
iface[16] = "", *p;
struct lws *wsi = *pwsi;
lwsl_err("%s: Too many redirects\n", __func__);
return NULL;
}
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
if (p)
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
if (p)
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
if (p)
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
if (p)
lwsl_info("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
address, port, path, ssl);
/* close the connection by hand */
#ifdef LWS_OPENSSL_SUPPORT
lws_ssl_close(wsi);
#endif
if (LWS_LIBUV_ENABLED(wsi->context)) {
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
/*
* libuv has to do his own close handle processing asynchronously
* but once it starts we can do everything else synchronously,
* including trash wsi->desc.sockfd since it took a copy.
*
* When it completes it will call compatible_close()
*/
lws_libuv_closehandle_manually(wsi);
} else
#else
compatible_close(wsi->desc.sockfd);
#ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = ssl;
#else
if (ssl) {
lwsl_err("%s: not configured for ssl\n", __func__);
return NULL;
}
#endif
wsi->desc.sockfd = LWS_SOCK_INVALID;
wsi->state = LWSS_CLIENT_UNCONNECTED;
wsi->protocol = NULL;
wsi->pending_timeout = NO_PENDING_TIMEOUT;
wsi->hdr_parsing_completed = 0;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
return NULL;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
return NULL;
if (origin[0])
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
origin))
return NULL;
if (protocol[0])
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
protocol))
return NULL;
if (method[0])
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
method))
return NULL;
if (iface[0])
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
iface))
return NULL;
origin[0] = '/';
strncpy(&origin[1], path, sizeof(origin) - 2);
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
return NULL;
*pwsi = lws_client_connect_2(wsi);
return *pwsi;
static hubbub_error
html_parser_cb(const hubbub_token *token, void *pw)
{
struct lws_rewrite *r = (struct lws_rewrite *)pw;
char buf[1024], *start = buf + LWS_PRE, *p = start,
*end = &buf[sizeof(buf) - 1];
size_t i;
switch (token->type) {
case HUBBUB_TOKEN_DOCTYPE:
(int) token->data.doctype.name.len,
token->data.doctype.name.ptr,
token->data.doctype.force_quirks ?
"(force-quirks) " : "");
if (token->data.doctype.public_missing)
(int) token->data.doctype.public_id.len,
token->data.doctype.public_id.ptr);
if (token->data.doctype.system_missing)
(int) token->data.doctype.system_id.len,
token->data.doctype.system_id.ptr);
break;
case HUBBUB_TOKEN_START_TAG:
p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
token->data.tag.name.ptr);
/* (token->data.tag.self_closing) ?
"(self-closing) " : "",
(token->data.tag.n_attributes > 0) ?
"attributes:" : "");
*/
for (i = 0; i < token->data.tag.n_attributes; i++) {
if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
!hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
!hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
int plen = (int) token->data.tag.attributes[i].value.len;
if (strncmp(pp, "http:", 5) && strncmp(pp, "https:", 6)) {
if (!hstrcmp(&token->data.tag.attributes[i].value,
r->from, r->from_len)) {
pp += r->from_len;
plen -= r->from_len;
}
p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
r->to, plen, pp);
continue;
}
p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
(int) token->data.tag.attributes[i].value.len,
token->data.tag.attributes[i].value.ptr);
p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
token->data.tag.name.ptr);
/*
(token->data.tag.self_closing) ?
"(self-closing) " : "",
(token->data.tag.n_attributes > 0) ?
"attributes:" : "");
*/
for (i = 0; i < token->data.tag.n_attributes; i++) {
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
(int) token->data.tag.attributes[i].value.len,
token->data.tag.attributes[i].value.ptr);
}
(int) token->data.comment.len,
token->data.comment.ptr);
break;
case HUBBUB_TOKEN_CHARACTER:
if (token->data.character.len == 1) {
if (*token->data.character.ptr == '<') {
p += lws_snprintf(p, end - p, "<");
break;
}
if (*token->data.character.ptr == '>') {
p += lws_snprintf(p, end - p, ">");
break;
}
if (*token->data.character.ptr == '&') {
p += lws_snprintf(p, end - p, "&");
break;
}
}
p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
token->data.character.ptr);
break;
case HUBBUB_TOKEN_EOF:
break;
}
if (user_callback_handle_rxflow(r->wsi->protocol->callback,
r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
r->wsi->user_space, start, p - start))
return -1;
return HUBBUB_OK;
}
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
static char *
lws_strdup(const char *s)
{
char *d = lws_malloc(strlen(s) + 1, "strdup");
if (d)
strcpy(d, s);
return d;
}
void
lws_client_stash_destroy(struct lws *wsi)
{
if (!wsi || !wsi->stash)
return;
lws_free_set_NULL(wsi->stash->address);
lws_free_set_NULL(wsi->stash->path);
lws_free_set_NULL(wsi->stash->host);
lws_free_set_NULL(wsi->stash->origin);
lws_free_set_NULL(wsi->stash->protocol);
lws_free_set_NULL(wsi->stash->method);
lws_free_set_NULL(wsi->stash->iface);
lws_free_set_NULL(wsi->stash);
}
LWS_VISIBLE struct lws *
lws_client_connect_via_info(struct lws_client_connect_info *i)
struct lws *wsi;
const struct lws_protocols *p;
const char *local = i->protocol;
if (i->context->requested_kill)
return NULL;
if (!i->context->protocol_init_done)
lws_protocol_init(i->context);
/*
* If we have .local_protocol_name, use it to select the
* local protocol handler to bind to. Otherwise use .protocol if
* http[s].
*/
if (i->local_protocol_name)
local = i->local_protocol_name;
/* assert the mode and union status (hdr) clearly */
lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
wsi->desc.sockfd = LWS_SOCK_INVALID;
/* 1) fill up the wsi with stuff from the connect_info as far as it
* can go. It's because not only is our connection async, we might
* not even be able to get ahold of an ah at this point.
*/
if (!i->method) { /* ie, ws */
/* allocate the ws struct for the wsi */
wsi->ws = lws_zalloc(sizeof(*wsi->ws), "client ws struct");
if (!wsi->ws) {
lwsl_notice("OOM\n");
goto bail;
}
/* -1 means just use latest supported */
if (i->ietf_version_or_minus_one != -1 &&
i->ietf_version_or_minus_one)
v = i->ietf_version_or_minus_one;
wsi->ws->ietf_spec_revision = v;
}
wsi->position_in_fds_table = -1;
wsi->vhost = i->vhost;
if (!wsi->vhost)
wsi->vhost = i->context->vhost_list;
if (!wsi->vhost) {
lwsl_err("At least one vhost in the context is required\n");
goto bail;
}
wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE);
/*
* 1) for http[s] connection, allow protocol selection by name
* 2) for ws[s], if local_protocol_name given also use it for
* local protocol binding... this defeats the server
* protocol negotiation if so
*
* Otherwise leave at protocols[0]... the server will tell us
* which protocol we are associated with since we can give it a
* list.
*/
lwsl_info("binding to %s\n", local);
p = lws_vhost_name_to_protocol(wsi->vhost, local);
if (p)
wsi->protocol = p;
}
if (wsi && !wsi->user_space && i->userdata) {
wsi->user_space_externally_allocated = 1;
wsi->user_space = i->userdata;
} else
/* if we stay in http, we can assign the user space now,
* otherwise do it after the protocol negotiated
*/
if (i->method)
if (lws_ensure_user_space(wsi))
goto bail;
#ifdef LWS_OPENSSL_SUPPORT
if (!i->method) /* !!! disallow ws for h2 right now */
wsi->use_ssl |= LCCSCF_NOT_H2;
lwsl_err("libwebsockets not configured for ssl\n");
goto bail;
}
/* 2) stash the things from connect_info that we can't process without
* an ah. Because if no ah, we will go on the ah waiting list and
* process those things later (after the connect_info and maybe the
* things pointed to have gone out of scope.
*/
wsi->stash = lws_zalloc(sizeof(*wsi->stash), "client stash");
lwsl_err("%s: OOM\n", __func__);
wsi->stash->address = lws_strdup(i->address);
wsi->stash->path = lws_strdup(i->path);
wsi->stash->host = lws_strdup(i->host);
if (!wsi->stash->address || !wsi->stash->path || !wsi->stash->host)
goto bail1;
if (i->origin) {
wsi->stash->origin = lws_strdup(i->origin);
if (!wsi->stash->origin)
goto bail1;
}
if (i->protocol) {
wsi->stash->protocol = lws_strdup(i->protocol);
if (!wsi->stash->protocol)
goto bail1;
}
if (i->method) {
wsi->stash->method = lws_strdup(i->method);
if (!wsi->stash->method)
goto bail1;
}
if (i->iface) {
wsi->stash->iface = lws_strdup(i->iface);
if (!wsi->stash->iface)
goto bail1;