1 #include "private-libwebsockets.h"
4 lws_client_connect_2(struct lws *wsi)
7 struct sockaddr_in6 server_addr6;
8 struct sockaddr_in6 client_addr6;
9 struct addrinfo hints, *result;
11 struct lws_context *context = wsi->context;
12 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
13 struct sockaddr_in server_addr4;
14 struct sockaddr_in client_addr4;
15 struct lws_pollfd pfd;
20 lwsl_client("%s\n", __func__);
24 if (context->http_proxy_port) {
25 plen = sprintf((char *)pt->serv_buf,
26 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
27 "User-agent: libwebsockets\x0d\x0a",
28 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
29 wsi->u.hdr.ah->c_port);
31 if (context->proxy_basic_auth_token[0])
32 plen += sprintf((char *)pt->serv_buf + plen,
33 "Proxy-authorization: basic %s\x0d\x0a",
34 context->proxy_basic_auth_token);
36 plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
37 ads = context->http_proxy_address;
40 if (LWS_IPV6_ENABLED(context)) {
41 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
42 server_addr6.sin6_port = htons(context->http_proxy_port);
45 server_addr4.sin_port = htons(context->http_proxy_port);
48 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
50 if (LWS_IPV6_ENABLED(context)) {
51 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
52 server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
55 server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
59 * prepare the actual connection (to the proxy, if any)
61 lwsl_client("%s: address %s\n", __func__, ads);
64 if (LWS_IPV6_ENABLED(context)) {
65 memset(&hints, 0, sizeof(struct addrinfo));
66 #if !defined(__ANDROID__)
67 hints.ai_family = AF_INET6;
68 hints.ai_flags = AI_V4MAPPED;
70 n = getaddrinfo(ads, NULL, &hints, &result);
73 lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
75 lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
80 server_addr6.sin6_family = AF_INET6;
81 switch (result->ai_family) {
82 #if defined(__ANDROID__)
84 /* map IPv4 to IPv6 */
85 bzero((char *)&server_addr6.sin6_addr,
86 sizeof(struct in6_addr));
87 server_addr6.sin6_addr.s6_addr[10] = 0xff;
88 server_addr6.sin6_addr.s6_addr[11] = 0xff;
89 memcpy(&server_addr6.sin6_addr.s6_addr[12],
90 &((struct sockaddr_in *)result->ai_addr)->sin_addr,
91 sizeof(struct in_addr));
95 memcpy(&server_addr6.sin6_addr,
96 &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
97 sizeof(struct in6_addr));
100 lwsl_err("Unknown address family\n");
101 freeaddrinfo(result);
105 freeaddrinfo(result);
109 struct addrinfo ai, *res, *result;
112 memset (&ai, 0, sizeof ai);
113 ai.ai_family = PF_UNSPEC;
114 ai.ai_socktype = SOCK_STREAM;
115 ai.ai_flags = AI_CANONNAME;
117 if (getaddrinfo(ads, NULL, &ai, &result))
122 switch (res->ai_family) {
124 p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
132 freeaddrinfo(result);
136 server_addr4.sin_family = AF_INET;
137 server_addr4.sin_addr = *((struct in_addr *)p);
138 bzero(&server_addr4.sin_zero, 8);
139 freeaddrinfo(result);
142 if (!lws_socket_is_valid(wsi->sock)) {
145 if (LWS_IPV6_ENABLED(context))
146 wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
149 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
151 if (!lws_socket_is_valid(wsi->sock)) {
152 lwsl_warn("Unable to open socket\n");
156 if (lws_plat_set_socket_options(context, wsi->sock)) {
157 lwsl_err("Failed to set wsi socket options\n");
158 compatible_close(wsi->sock);
162 wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
164 lws_libev_accept(wsi, wsi->sock);
165 if (insert_wsi_socket_into_fds(context, wsi)) {
166 compatible_close(wsi->sock);
171 * past here, we can't simply free the structs as error
172 * handling as oom4 does. We have to run the whole close flow.
174 wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
175 wsi->user_space, NULL, 0);
177 PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
180 if (LWS_IPV6_ENABLED(context)) {
181 v = (struct sockaddr *)&client_addr6;
182 n = sizeof(client_addr6);
184 client_addr6.sin6_family = AF_INET6;
188 v = (struct sockaddr *)&client_addr4;
189 n = sizeof(client_addr4);
191 client_addr4.sin_family = AF_INET;
194 if (context->iface) {
195 if (interface_to_sa(context, context->iface,
196 (struct sockaddr_in *)v, n) < 0) {
197 lwsl_err("Unable to find interface %s\n",
202 if (bind(wsi->sock, v, n) < 0) {
203 lwsl_err("Error binding to interface %s",
211 if (LWS_IPV6_ENABLED(context)) {
212 v = (struct sockaddr *)&server_addr6;
213 n = sizeof(struct sockaddr_in6);
217 v = (struct sockaddr *)&server_addr4;
218 n = sizeof(struct sockaddr);
221 if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
222 if (LWS_ERRNO == LWS_EALREADY ||
223 LWS_ERRNO == LWS_EINPROGRESS ||
224 LWS_ERRNO == LWS_EWOULDBLOCK
226 || LWS_ERRNO == WSAEINVAL
229 lwsl_client("nonblocking connect retry\n");
232 * must do specifically a POLLOUT poll to hear
233 * about the connect completion
235 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
241 if (LWS_ERRNO != LWS_EISCONN) {
242 lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
247 lwsl_client("connected\n");
249 /* we are connected to server, or proxy */
251 if (context->http_proxy_port) {
254 * OK from now on we talk via the proxy, so connect to that
256 * (will overwrite existing pointer,
257 * leaving old string/frag there but unreferenced)
259 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
260 context->http_proxy_address))
262 wsi->u.hdr.ah->c_port = context->http_proxy_port;
264 n = send(wsi->sock, (char *)pt->serv_buf, plen,
267 lwsl_debug("ERROR writing to proxy socket\n");
271 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
274 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
280 * provoke service to issue the handshake directly
281 * we need to do it this way because in the proxy case, this is the
282 * next state and executed only if and when we get a good proxy
283 * response inside the state machine... but notice in SSL case this
284 * may not have sent anything yet with 0 return, and won't until some
285 * many retries from main loop. To stop that becoming endless,
286 * cover with a timeout.
289 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
292 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
294 pfd.revents = LWS_POLLIN;
296 n = lws_service_fd(context, &pfd);
299 if (n) /* returns 1 on failure after closing wsi */
305 /* we're closing, losing some rx is OK */
306 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
307 lws_header_table_detach(wsi);
308 /* take care that we might be inserted in fds already */
309 if (wsi->position_in_fds_table != -1)
316 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
322 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
323 * this only works if still in HTTP, ie, not upgraded yet
324 * wsi: connection to reset
325 * address: network address of the new server
326 * port: port to connect to
327 * path: uri path to connect to on the new server
328 * host: host header to send to the new server
330 LWS_VISIBLE struct lws *
331 lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host)
333 if (wsi->u.hdr.redirects == 3) {
334 lwsl_err("%s: Too many redirects\n", __func__);
337 wsi->u.hdr.redirects++;
339 #ifdef LWS_OPENSSL_SUPPORT
343 lwsl_err("%s: not configured for ssl\n", __func__);
348 lwsl_notice("redirect ads='%s', port=%d, path='%s'\n", address, port, path);
350 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
353 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
356 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
359 compatible_close(wsi->sock);
360 remove_wsi_socket_from_fds(wsi);
361 wsi->sock = LWS_SOCK_INVALID;
362 wsi->state = LWSS_CLIENT_UNCONNECTED;
363 wsi->protocol = NULL;
364 wsi->pending_timeout = NO_PENDING_TIMEOUT;
365 wsi->u.hdr.ah->c_port = port;
367 return lws_client_connect_2(wsi);
371 * lws_client_connect_via_info() - Connect to another websocket server
372 * @i:pointer to lws_client_connect_info struct
374 * This function creates a connection to a remote server
378 LWS_VISIBLE struct lws *
379 lws_client_connect_via_info(struct lws_client_connect_info *i)
382 int v = SPEC_LATEST_SUPPORTED;
384 wsi = lws_zalloc(sizeof(struct lws));
388 wsi->context = i->context;
389 wsi->sock = LWS_SOCK_INVALID;
391 /* -1 means just use latest supported */
393 if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
394 v = i->ietf_version_or_minus_one;
396 wsi->ietf_spec_revision = v;
397 wsi->user_space = NULL;
398 wsi->state = LWSS_CLIENT_UNCONNECTED;
399 wsi->protocol = NULL;
400 wsi->pending_timeout = NO_PENDING_TIMEOUT;
401 wsi->position_in_fds_table = -1;
403 #ifdef LWS_OPENSSL_SUPPORT
404 wsi->use_ssl = i->ssl_connection;
406 if (i->ssl_connection) {
407 lwsl_err("libwebsockets not configured for ssl\n");
412 if (lws_header_table_attach(wsi))
416 * we're not necessarily in a position to action these right away,
417 * stash them... we only need during connect phase so u.hdr is fine
419 wsi->u.hdr.ah->c_port = i->port;
420 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, i->address))
423 /* these only need u.hdr lifetime as well */
425 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, i->path))
428 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, i->host))
432 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, i->origin))
435 * this is a list of protocols we tell the server we're okay with
436 * stash it for later when we compare server response with it
439 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
443 wsi->protocol = &i->context->protocols[0];
444 if (wsi && !wsi->user_space && i->userdata) {
445 wsi->user_space_externally_allocated = 1;
446 wsi->user_space = i->userdata;
450 * Check with each extension if it is able to route and proxy this
451 * connection for us. For example, an extension like x-google-mux
452 * can handle this and then we don't need an actual socket for this
456 if (lws_ext_cb_all_exts(i->context, wsi,
457 LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
458 (void *)i->address, i->port) > 0) {
459 lwsl_client("lws_client_connect: ext handling conn\n");
462 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
465 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
468 lwsl_client("lws_client_connect: direct conn\n");
470 wsi->context->count_wsi_allocated++;
472 return lws_client_connect_2(wsi);
475 /* we're closing, losing some rx is OK */
476 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
477 lws_header_table_detach(wsi);
486 * lws_client_connect_extended() - Connect to another websocket server
487 * DEPRECATED use lws_client_connect_via_info
488 * @context: Websocket context
489 * @address: Remote server address, eg, "myserver.com"
490 * @port: Port to connect to on the remote server, eg, 80
491 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
493 * @path: Websocket path on server
494 * @host: Hostname on server
495 * @origin: Socket origin name
496 * @protocol: Comma-separated list of protocols being asked for from
497 * the server, or just one. The server will pick the one it
499 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
500 * protocol supported, or the specific protocol ordinal
501 * @userdata: Pre-allocated user data
503 * This function creates a connection to a remote server
506 LWS_VISIBLE struct lws *
507 lws_client_connect_extended(struct lws_context *context, const char *address,
508 int port, int ssl_connection, const char *path,
509 const char *host, const char *origin,
510 const char *protocol, int ietf_version_or_minus_one,
513 struct lws_client_connect_info i;
515 memset(&i, 0, sizeof(i));
520 i.ssl_connection = ssl_connection;
524 i.protocol = protocol;
525 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
526 i.userdata = userdata;
528 return lws_client_connect_via_info(&i);
531 * lws_client_connect_info() - Connect to another websocket server
532 * DEPRECATED use lws_client_connect_via_info
533 * @context: Websocket context
534 * @address: Remote server address, eg, "myserver.com"
535 * @port: Port to connect to on the remote server, eg, 80
536 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
538 * @path: Websocket path on server
539 * @host: Hostname on server
540 * @origin: Socket origin name
541 * @protocol: Comma-separated list of protocols being asked for from
542 * the server, or just one. The server will pick the one it
543 * likes best. If you don't want to specify a protocol, which is
544 * legal, use NULL here.
545 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
546 * protocol supported, or the specific protocol ordinal
548 * This function creates a connection to a remote server
552 LWS_VISIBLE struct lws *
553 lws_client_connect(struct lws_context *context, const char *address,
554 int port, int ssl_connection, const char *path,
555 const char *host, const char *origin,
556 const char *protocol, int ietf_version_or_minus_one)
558 struct lws_client_connect_info i;
560 memset(&i, 0, sizeof(i));
565 i.ssl_connection = ssl_connection;
569 i.protocol = protocol;
570 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
573 return lws_client_connect_via_info(&i);