Newer
Older
lws_client_connect_2(struct lws *wsi)
struct sockaddr_in6 server_addr6;
struct sockaddr_in6 client_addr6;
struct addrinfo hints, *result;
#endif
struct lws_context *context = wsi->context;
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
struct sockaddr_in server_addr4;
struct sockaddr_in client_addr4;
lwsl_client("%s\n", __func__);
"CONNECT %s:%u HTTP/1.0\x0d\x0a"
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
"Proxy-authorization: basic %s\x0d\x0a",
context->proxy_basic_auth_token);
ads = context->http_proxy_address;
if (LWS_IPV6_ENABLED(context)) {
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
server_addr6.sin6_port = htons(context->http_proxy_port);
#endif
server_addr4.sin_port = htons(context->http_proxy_port);
} else {
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
if (LWS_IPV6_ENABLED(context)) {
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
#endif
server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
}
/*
* prepare the actual connection (to the proxy, if any)
*/
if (LWS_IPV6_ENABLED(context)) {
memset(&hints, 0, sizeof(struct addrinfo));
#if !defined(__ANDROID__)
hints.ai_family = AF_INET6;
hints.ai_flags = AI_V4MAPPED;
#ifdef _WIN32
lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
#else
goto oom4;
}
server_addr6.sin6_family = AF_INET6;
switch (result->ai_family) {
#if defined(__ANDROID__)
case AF_INET:
/* map IPv4 to IPv6 */
bzero((char *)&server_addr6.sin6_addr,
sizeof(struct in6_addr));
server_addr6.sin6_addr.s6_addr[10] = 0xff;
server_addr6.sin6_addr.s6_addr[11] = 0xff;
memcpy(&server_addr6.sin6_addr.s6_addr[12],
&((struct sockaddr_in *)result->ai_addr)->sin_addr,
sizeof(struct in_addr));
break;
#endif
case AF_INET6:
memcpy(&server_addr6.sin6_addr,
&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
sizeof(struct in6_addr));
break;
default:
lwsl_err("Unknown address family\n");
freeaddrinfo(result);
goto oom4;
}
freeaddrinfo(result);
} else
#endif
{
void *p = NULL;
memset (&ai, 0, sizeof ai);
ai.ai_family = PF_UNSPEC;
ai.ai_socktype = SOCK_STREAM;
ai.ai_flags = AI_CANONNAME;
if (getaddrinfo(ads, NULL, &ai, &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;
server_addr4.sin_addr = *((struct in_addr *)p);
if (!lws_socket_is_valid(wsi->sock)) {
if (LWS_IPV6_ENABLED(context))
wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
if (!lws_socket_is_valid(wsi->sock)) {
lwsl_warn("Unable to open socket\n");
goto oom4;
}
if (lws_plat_set_socket_options(context, wsi->sock)) {
lwsl_err("Failed to set wsi socket options\n");
compatible_close(wsi->sock);
goto oom4;
}
lws_libev_accept(wsi, wsi->sock);
if (insert_wsi_socket_into_fds(context, wsi)) {
compatible_close(wsi->sock);
/*
* past here, we can't simply free the structs as error
* handling as oom4 does. We have to run the whole close flow.
*/
PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
if (LWS_IPV6_ENABLED(context)) {
v = (struct sockaddr *)&client_addr6;
n = sizeof(client_addr6);
bzero((char *)v, n);
client_addr6.sin6_family = AF_INET6;
} else
#endif
{
v = (struct sockaddr *)&client_addr4;
n = sizeof(client_addr4);
bzero((char *)v, n);
client_addr4.sin_family = AF_INET;
}
if (context->iface) {
if (interface_to_sa(context, context->iface,
(struct sockaddr_in *)v, n) < 0) {
lwsl_err("Unable to find interface %s\n",
context->iface);
if (bind(wsi->sock, v, n) < 0) {
lwsl_err("Error binding to interface %s",
context->iface);
if (LWS_IPV6_ENABLED(context)) {
v = (struct sockaddr *)&server_addr6;
n = sizeof(struct sockaddr_in6);
} else
#endif
{
v = (struct sockaddr *)&server_addr4;
n = sizeof(struct sockaddr);
}
if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
if (LWS_ERRNO == LWS_EALREADY ||
LWS_ERRNO == LWS_EINPROGRESS ||
LWS_ERRNO == LWS_EWOULDBLOCK
#ifdef _WIN32
|| LWS_ERRNO == WSAEINVAL
#endif
lwsl_client("nonblocking connect retry\n");
/*
* must do specifically a POLLOUT poll to hear
* about the connect completion
*/
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
if (LWS_ERRNO != LWS_EISCONN) {
lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
goto failed;
}
/* we are connected to server, or proxy */
if (context->http_proxy_port) {
* 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,
goto failed;
wsi->u.hdr.ah->c_port = context->http_proxy_port;
lwsl_debug("ERROR writing to proxy socket\n");
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
AWAITING_TIMEOUT);
return wsi;
}
/*
* 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 some
* 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.revents = LWS_POLLIN;
n = lws_service_fd(context, &pfd);
if (n) /* returns 1 on failure after closing wsi */
return NULL;
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/**
* 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 *wsi, int ssl, const char *address, int port, const char *path, const char *host)
{
if (wsi->u.hdr.redirects == 3) {
lwsl_err("%s: Too many redirects\n", __func__);
return NULL;
}
wsi->u.hdr.redirects++;
#ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = ssl;
#else
if (ssl) {
lwsl_err("%s: not configured for ssl\n", __func__);
return NULL;
}
#endif
lwsl_notice("redirect ads='%s', port=%d, path='%s'\n", address, port, path);
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
return NULL;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
return NULL;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
return NULL;
remove_wsi_socket_from_fds(wsi);
wsi->sock = LWS_SOCK_INVALID;
wsi->state = LWSS_CLIENT_UNCONNECTED;
wsi->protocol = NULL;
wsi->pending_timeout = NO_PENDING_TIMEOUT;
wsi->u.hdr.ah->c_port = port;
return lws_client_connect_2(wsi);
}
* lws_client_connect_via_info() - Connect to another websocket server
* @i:pointer to lws_client_connect_info struct
*
* This function creates a connection to a remote server
*/
LWS_VISIBLE struct lws *
lws_client_connect_via_info(struct lws_client_connect_info *i)
struct lws *wsi;
wsi = lws_zalloc(sizeof(struct lws));
wsi->sock = LWS_SOCK_INVALID;
/* -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;
#ifdef LWS_OPENSSL_SUPPORT
lwsl_err("libwebsockets not configured for ssl\n");
goto bail;
}
if (lws_allocate_header_table(wsi))
goto bail;
/*
* we're not necessarily in a position to action these right away,
* stash them... we only need during connect phase so u.hdr is fine
*/
wsi->u.hdr.ah->c_port = i->port;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, i->address))
/* these only need u.hdr lifetime as well */
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, i->path))
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, i->host))
if (i->origin)
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, i->origin))
goto bail1;
/*
* this is a list of protocols we tell the server we're okay with
* stash it for later when we compare server response with it
*/
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
wsi->protocol = &i->context->protocols[0];
if (wsi && !wsi->user_space && i->userdata) {
wsi->user_space_externally_allocated = 1;
wsi->user_space = i->userdata;
}
* Check with each extension if it is able to route and proxy this
* connection for us. For example, an extension like x-google-mux
* can handle this and then we don't need an actual socket for this
* connection.
if (lws_ext_cb_all_exts(i->context, wsi,
LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
(void *)i->address, i->port) > 0) {
lwsl_client("lws_client_connect: ext handling conn\n");
lwsl_client("lws_client_connect: direct conn\n");
* lws_client_connect_extended() - Connect to another websocket server
* @context: Websocket context
* @address: Remote server address, eg, "myserver.com"
* @port: Port to connect to on the remote server, eg, 80
* @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
* signed certs
* @path: Websocket path on server
* @host: Hostname on server
* @origin: Socket origin name
* @protocol: Comma-separated list of protocols being asked for from
* the server, or just one. The server will pick the one it
* likes best.
* @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
* @userdata: Pre-allocated user data
*
* This function creates a connection to a remote server
*/
LWS_VISIBLE struct lws *
lws_client_connect_extended(struct lws_context *context, const char *address,
int port, int ssl_connection, const char *path,
const char *host, const char *origin,
const char *protocol, int ietf_version_or_minus_one,
void *userdata)
struct lws_client_connect_info i;
memset(&i, 0, sizeof(i));
i.context = context;
i.address = address;
i.port = port;
i.ssl_connection = ssl_connection;
i.path = path;
i.host = host;
i.origin = origin;
i.protocol = protocol;
i.ietf_version_or_minus_one = ietf_version_or_minus_one;
i.userdata = userdata;
/**
* lws_client_connect_info() - Connect to another websocket server
* DEPRECATED use lws_client_connect_via_info
* @context: Websocket context
* @address: Remote server address, eg, "myserver.com"
* @port: Port to connect to on the remote server, eg, 80
* @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
* signed certs
* @path: Websocket path on server
* @host: Hostname on server
* @origin: Socket origin name
* @protocol: Comma-separated list of protocols being asked for from
* the server, or just one. The server will pick the one it
* likes best. If you don't want to specify a protocol, which is
* legal, use NULL here.
* @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
* protocol supported, or the specific protocol ordinal
*
* This function creates a connection to a remote server
*/
LWS_VISIBLE struct lws *
lws_client_connect(struct lws_context *context, const char *address,
int port, int ssl_connection, const char *path,
const char *host, const char *origin,
const char *protocol, int ietf_version_or_minus_one)
{
return lws_client_connect_extended(context, address, port, ssl_connection, path,