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.
176 PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
179 if (LWS_IPV6_ENABLED(context)) {
180 v = (struct sockaddr *)&client_addr6;
181 n = sizeof(client_addr6);
183 client_addr6.sin6_family = AF_INET6;
187 v = (struct sockaddr *)&client_addr4;
188 n = sizeof(client_addr4);
190 client_addr4.sin_family = AF_INET;
193 if (context->iface) {
194 if (interface_to_sa(context, context->iface,
195 (struct sockaddr_in *)v, n) < 0) {
196 lwsl_err("Unable to find interface %s\n",
201 if (bind(wsi->sock, v, n) < 0) {
202 lwsl_err("Error binding to interface %s",
210 if (LWS_IPV6_ENABLED(context)) {
211 v = (struct sockaddr *)&server_addr6;
212 n = sizeof(struct sockaddr_in6);
216 v = (struct sockaddr *)&server_addr4;
217 n = sizeof(struct sockaddr);
220 if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
221 if (LWS_ERRNO == LWS_EALREADY ||
222 LWS_ERRNO == LWS_EINPROGRESS ||
223 LWS_ERRNO == LWS_EWOULDBLOCK
225 || LWS_ERRNO == WSAEINVAL
228 lwsl_client("nonblocking connect retry\n");
231 * must do specifically a POLLOUT poll to hear
232 * about the connect completion
234 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
240 if (LWS_ERRNO != LWS_EISCONN) {
241 lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
246 lwsl_client("connected\n");
248 /* we are connected to server, or proxy */
250 if (context->http_proxy_port) {
253 * OK from now on we talk via the proxy, so connect to that
255 * (will overwrite existing pointer,
256 * leaving old string/frag there but unreferenced)
258 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
259 context->http_proxy_address))
261 wsi->u.hdr.ah->c_port = context->http_proxy_port;
263 n = send(wsi->sock, (char *)pt->serv_buf, plen,
266 lwsl_debug("ERROR writing to proxy socket\n");
270 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
273 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
279 * provoke service to issue the handshake directly
280 * we need to do it this way because in the proxy case, this is the
281 * next state and executed only if and when we get a good proxy
282 * response inside the state machine... but notice in SSL case this
283 * may not have sent anything yet with 0 return, and won't until some
284 * many retries from main loop. To stop that becoming endless,
285 * cover with a timeout.
288 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
291 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
293 pfd.revents = LWS_POLLIN;
295 n = lws_service_fd(context, &pfd);
298 if (n) /* returns 1 on failure after closing wsi */
304 /* we're closing, losing some rx is OK */
305 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
306 lws_header_table_detach(wsi, 0);
312 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
318 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
319 * this only works if still in HTTP, ie, not upgraded yet
320 * wsi: connection to reset
321 * address: network address of the new server
322 * port: port to connect to
323 * path: uri path to connect to on the new server
324 * host: host header to send to the new server
326 LWS_VISIBLE struct lws *
327 lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host)
329 if (wsi->u.hdr.redirects == 3) {
330 lwsl_err("%s: Too many redirects\n", __func__);
333 wsi->u.hdr.redirects++;
335 #ifdef LWS_OPENSSL_SUPPORT
339 lwsl_err("%s: not configured for ssl\n", __func__);
344 lwsl_notice("redirect ads='%s', port=%d, path='%s'\n", address, port, path);
346 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
349 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
352 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
355 compatible_close(wsi->sock);
356 remove_wsi_socket_from_fds(wsi);
357 wsi->sock = LWS_SOCK_INVALID;
358 wsi->state = LWSS_CLIENT_UNCONNECTED;
359 wsi->protocol = NULL;
360 wsi->pending_timeout = NO_PENDING_TIMEOUT;
361 wsi->u.hdr.ah->c_port = port;
363 return lws_client_connect_2(wsi);
367 * lws_client_connect_via_info() - Connect to another websocket server
368 * @i:pointer to lws_client_connect_info struct
370 * This function creates a connection to a remote server
374 LWS_VISIBLE struct lws *
375 lws_client_connect_via_info(struct lws_client_connect_info *i)
378 int v = SPEC_LATEST_SUPPORTED;
380 wsi = lws_zalloc(sizeof(struct lws));
384 wsi->context = i->context;
385 wsi->sock = LWS_SOCK_INVALID;
387 /* -1 means just use latest supported */
389 if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
390 v = i->ietf_version_or_minus_one;
392 wsi->ietf_spec_revision = v;
393 wsi->user_space = NULL;
394 wsi->state = LWSS_CLIENT_UNCONNECTED;
395 wsi->protocol = NULL;
396 wsi->pending_timeout = NO_PENDING_TIMEOUT;
397 wsi->position_in_fds_table = -1;
399 #ifdef LWS_OPENSSL_SUPPORT
400 wsi->use_ssl = i->ssl_connection;
402 if (i->ssl_connection) {
403 lwsl_err("libwebsockets not configured for ssl\n");
408 if (lws_header_table_attach(wsi, 0))
412 * we're not necessarily in a position to action these right away,
413 * stash them... we only need during connect phase so u.hdr is fine
415 wsi->u.hdr.ah->c_port = i->port;
416 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, i->address))
419 /* these only need u.hdr lifetime as well */
421 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, i->path))
424 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, i->host))
428 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, i->origin))
431 * this is a list of protocols we tell the server we're okay with
432 * stash it for later when we compare server response with it
435 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
439 wsi->protocol = &i->context->protocols[0];
440 if (wsi && !wsi->user_space && i->userdata) {
441 wsi->user_space_externally_allocated = 1;
442 wsi->user_space = i->userdata;
446 * Check with each extension if it is able to route and proxy this
447 * connection for us. For example, an extension like x-google-mux
448 * can handle this and then we don't need an actual socket for this
452 if (lws_ext_cb_all_exts(i->context, wsi,
453 LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
454 (void *)i->address, i->port) > 0) {
455 lwsl_client("lws_client_connect: ext handling conn\n");
458 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
461 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
464 lwsl_client("lws_client_connect: direct conn\n");
466 wsi->context->count_wsi_allocated++;
468 return lws_client_connect_2(wsi);
471 /* we're closing, losing some rx is OK */
472 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
473 lws_header_table_detach(wsi, 0);
482 * lws_client_connect_extended() - Connect to another websocket server
483 * DEPRECATED use lws_client_connect_via_info
484 * @context: Websocket context
485 * @address: Remote server address, eg, "myserver.com"
486 * @port: Port to connect to on the remote server, eg, 80
487 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
489 * @path: Websocket path on server
490 * @host: Hostname on server
491 * @origin: Socket origin name
492 * @protocol: Comma-separated list of protocols being asked for from
493 * the server, or just one. The server will pick the one it
495 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
496 * protocol supported, or the specific protocol ordinal
497 * @userdata: Pre-allocated user data
499 * This function creates a connection to a remote server
502 LWS_VISIBLE struct lws *
503 lws_client_connect_extended(struct lws_context *context, const char *address,
504 int port, int ssl_connection, const char *path,
505 const char *host, const char *origin,
506 const char *protocol, int ietf_version_or_minus_one,
509 struct lws_client_connect_info i;
511 memset(&i, 0, sizeof(i));
516 i.ssl_connection = ssl_connection;
520 i.protocol = protocol;
521 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
522 i.userdata = userdata;
524 return lws_client_connect_via_info(&i);
527 * lws_client_connect_info() - Connect to another websocket server
528 * DEPRECATED use lws_client_connect_via_info
529 * @context: Websocket context
530 * @address: Remote server address, eg, "myserver.com"
531 * @port: Port to connect to on the remote server, eg, 80
532 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
534 * @path: Websocket path on server
535 * @host: Hostname on server
536 * @origin: Socket origin name
537 * @protocol: Comma-separated list of protocols being asked for from
538 * the server, or just one. The server will pick the one it
539 * likes best. If you don't want to specify a protocol, which is
540 * legal, use NULL here.
541 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
542 * protocol supported, or the specific protocol ordinal
544 * This function creates a connection to a remote server
548 LWS_VISIBLE struct lws *
549 lws_client_connect(struct lws_context *context, const char *address,
550 int port, int ssl_connection, const char *path,
551 const char *host, const char *origin,
552 const char *protocol, int ietf_version_or_minus_one)
554 struct lws_client_connect_info i;
556 memset(&i, 0, sizeof(i));
561 i.ssl_connection = ssl_connection;
565 i.protocol = protocol;
566 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
569 return lws_client_connect_via_info(&i);