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;
18 lwsl_client("%s\n", __func__);
22 if (wsi->vhost->http_proxy_port) {
23 plen = sprintf((char *)pt->serv_buf,
24 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
25 "User-agent: libwebsockets\x0d\x0a",
26 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
29 if (wsi->vhost->proxy_basic_auth_token[0])
30 plen += sprintf((char *)pt->serv_buf + plen,
31 "Proxy-authorization: basic %s\x0d\x0a",
32 wsi->vhost->proxy_basic_auth_token);
34 plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
35 ads = wsi->vhost->http_proxy_address;
38 if (LWS_IPV6_ENABLED(context)) {
39 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
40 server_addr6.sin6_port = htons(wsi->vhost->http_proxy_port);
43 server_addr4.sin_port = htons(wsi->vhost->http_proxy_port);
46 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
48 if (LWS_IPV6_ENABLED(context)) {
49 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
50 server_addr6.sin6_port = htons(wsi->u.hdr.c_port);
53 server_addr4.sin_port = htons(wsi->u.hdr.c_port);
57 * prepare the actual connection (to the proxy, if any)
59 lwsl_client("%s: address %s\n", __func__, ads);
62 if (LWS_IPV6_ENABLED(context)) {
63 memset(&hints, 0, sizeof(struct addrinfo));
64 #if !defined(__ANDROID__)
65 hints.ai_family = AF_INET6;
66 hints.ai_flags = AI_V4MAPPED;
68 n = getaddrinfo(ads, NULL, &hints, &result);
71 lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
73 lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
78 server_addr6.sin6_family = AF_INET6;
79 switch (result->ai_family) {
80 #if defined(__ANDROID__)
82 /* map IPv4 to IPv6 */
83 bzero((char *)&server_addr6.sin6_addr,
84 sizeof(struct in6_addr));
85 server_addr6.sin6_addr.s6_addr[10] = 0xff;
86 server_addr6.sin6_addr.s6_addr[11] = 0xff;
87 memcpy(&server_addr6.sin6_addr.s6_addr[12],
88 &((struct sockaddr_in *)result->ai_addr)->sin_addr,
89 sizeof(struct in_addr));
93 memcpy(&server_addr6.sin6_addr,
94 &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
95 sizeof(struct in6_addr));
98 lwsl_err("Unknown address family\n");
103 freeaddrinfo(result);
107 struct addrinfo ai, *res, *result;
110 memset (&ai, 0, sizeof ai);
111 ai.ai_family = PF_UNSPEC;
112 ai.ai_socktype = SOCK_STREAM;
113 ai.ai_flags = AI_CANONNAME;
115 if (getaddrinfo(ads, NULL, &ai, &result)) {
116 lwsl_err("getaddrinfo failed\n");
122 switch (res->ai_family) {
124 p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
132 lwsl_err("Couldn't identify address\n");
133 freeaddrinfo(result);
137 server_addr4.sin_family = AF_INET;
138 server_addr4.sin_addr = *((struct in_addr *)p);
139 bzero(&server_addr4.sin_zero, 8);
140 freeaddrinfo(result);
143 if (!lws_socket_is_valid(wsi->sock)) {
146 if (LWS_IPV6_ENABLED(context))
147 wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
150 wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
152 if (!lws_socket_is_valid(wsi->sock)) {
153 lwsl_warn("Unable to open socket\n");
157 if (lws_plat_set_socket_options(wsi->vhost, wsi->sock)) {
158 lwsl_err("Failed to set wsi socket options\n");
159 compatible_close(wsi->sock);
163 wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
165 lws_libev_accept(wsi, wsi->sock);
166 lws_libuv_accept(wsi, wsi->sock);
167 if (insert_wsi_socket_into_fds(context, wsi)) {
168 compatible_close(wsi->sock);
173 * past here, we can't simply free the structs as error
174 * handling as oom4 does. We have to run the whole close flow.
178 wsi->protocol = &wsi->vhost->protocols[0];
180 wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
181 wsi->user_space, NULL, 0);
183 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
186 n = lws_socket_bind(wsi->vhost, wsi->sock, 0, wsi->vhost->iface);
192 if (LWS_IPV6_ENABLED(context)) {
193 v = (struct sockaddr *)&server_addr6;
194 n = sizeof(struct sockaddr_in6);
198 v = (struct sockaddr *)&server_addr4;
199 n = sizeof(struct sockaddr);
202 if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
203 if (LWS_ERRNO == LWS_EALREADY ||
204 LWS_ERRNO == LWS_EINPROGRESS ||
205 LWS_ERRNO == LWS_EWOULDBLOCK
207 || LWS_ERRNO == WSAEINVAL
210 lwsl_client("nonblocking connect retry\n");
213 * must do specifically a POLLOUT poll to hear
214 * about the connect completion
216 if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
222 if (LWS_ERRNO != LWS_EISCONN) {
223 lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
228 lwsl_client("connected\n");
230 /* we are connected to server, or proxy */
232 if (wsi->vhost->http_proxy_port) {
235 * OK from now on we talk via the proxy, so connect to that
237 * (will overwrite existing pointer,
238 * leaving old string/frag there but unreferenced)
240 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
241 wsi->vhost->http_proxy_address))
243 wsi->u.hdr.c_port = wsi->vhost->http_proxy_port;
245 n = send(wsi->sock, (char *)pt->serv_buf, plen,
248 lwsl_debug("ERROR writing to proxy socket\n");
252 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
255 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
261 * provoke service to issue the handshake directly
262 * we need to do it this way because in the proxy case, this is the
263 * next state and executed only if and when we get a good proxy
264 * response inside the state machine... but notice in SSL case this
265 * may not have sent anything yet with 0 return, and won't until some
266 * many retries from main loop. To stop that becoming endless,
267 * cover with a timeout.
270 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
273 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
275 pfd.events = LWS_POLLIN;
276 pfd.revents = LWS_POLLIN;
278 n = lws_service_fd(context, &pfd);
281 if (n) /* returns 1 on failure after closing wsi */
287 /* we're closing, losing some rx is OK */
288 wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
289 //lwsl_err("%d\n", wsi->mode);
290 if (wsi->mode == LWSCM_HTTP_CLIENT)
291 wsi->vhost->protocols[0].callback(wsi,
292 LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
293 wsi->user_space, NULL, 0);
294 /* take care that we might be inserted in fds already */
295 if (wsi->position_in_fds_table != -1)
297 lws_header_table_detach(wsi, 0);
303 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
309 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
310 * this only works if still in HTTP, ie, not upgraded yet
311 * wsi: connection to reset
312 * address: network address of the new server
313 * port: port to connect to
314 * path: uri path to connect to on the new server
315 * host: host header to send to the new server
317 LWS_VISIBLE struct lws *
318 lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host)
320 if (wsi->u.hdr.redirects == 3) {
321 lwsl_err("%s: Too many redirects\n", __func__);
324 wsi->u.hdr.redirects++;
326 #ifdef LWS_OPENSSL_SUPPORT
330 lwsl_err("%s: not configured for ssl\n", __func__);
335 lwsl_notice("redirect ads='%s', port=%d, path='%s'\n", address, port, path);
337 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
340 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
343 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
346 compatible_close(wsi->sock);
347 remove_wsi_socket_from_fds(wsi);
348 wsi->sock = LWS_SOCK_INVALID;
349 wsi->state = LWSS_CLIENT_UNCONNECTED;
350 wsi->protocol = NULL;
351 wsi->pending_timeout = NO_PENDING_TIMEOUT;
352 wsi->u.hdr.c_port = port;
354 return lws_client_connect_2(wsi);
357 #ifdef LWS_WITH_HTTP_PROXY
359 html_parser_cb(const hubbub_token *token, void *pw)
361 struct lws_rewrite *r = (struct lws_rewrite *)pw;
362 char buf[1024], *start = buf + LWS_PRE, *p = start,
363 *end = &buf[sizeof(buf) - 1];
366 switch (token->type) {
367 case HUBBUB_TOKEN_DOCTYPE:
369 p += snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
370 (int) token->data.doctype.name.len,
371 token->data.doctype.name.ptr,
372 token->data.doctype.force_quirks ?
373 "(force-quirks) " : "");
375 if (token->data.doctype.public_missing)
376 printf("\tpublic: missing\n");
378 p += snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
379 (int) token->data.doctype.public_id.len,
380 token->data.doctype.public_id.ptr);
382 if (token->data.doctype.system_missing)
383 printf("\tsystem: missing\n");
385 p += snprintf(p, end - p, " \"%.*s\">\n",
386 (int) token->data.doctype.system_id.len,
387 token->data.doctype.system_id.ptr);
390 case HUBBUB_TOKEN_START_TAG:
391 p += snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
392 token->data.tag.name.ptr);
394 /* (token->data.tag.self_closing) ?
395 "(self-closing) " : "",
396 (token->data.tag.n_attributes > 0) ?
399 for (i = 0; i < token->data.tag.n_attributes; i++) {
400 if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
401 !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
402 !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
403 const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
404 int plen = (int) token->data.tag.attributes[i].value.len;
406 if (!hstrcmp(&token->data.tag.attributes[i].value,
407 r->from, r->from_len)) {
411 p += snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
412 (int) token->data.tag.attributes[i].name.len,
413 token->data.tag.attributes[i].name.ptr,
418 p += snprintf(p, end - p, " %.*s=\"%.*s\"",
419 (int) token->data.tag.attributes[i].name.len,
420 token->data.tag.attributes[i].name.ptr,
421 (int) token->data.tag.attributes[i].value.len,
422 token->data.tag.attributes[i].value.ptr);
424 p += snprintf(p, end - p, ">\n");
426 case HUBBUB_TOKEN_END_TAG:
427 p += snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
428 token->data.tag.name.ptr);
430 (token->data.tag.self_closing) ?
431 "(self-closing) " : "",
432 (token->data.tag.n_attributes > 0) ?
435 for (i = 0; i < token->data.tag.n_attributes; i++) {
436 p += snprintf(p, end - p, " %.*s='%.*s'\n",
437 (int) token->data.tag.attributes[i].name.len,
438 token->data.tag.attributes[i].name.ptr,
439 (int) token->data.tag.attributes[i].value.len,
440 token->data.tag.attributes[i].value.ptr);
442 p += snprintf(p, end - p, ">\n");
444 case HUBBUB_TOKEN_COMMENT:
445 p += snprintf(p, end - p, "<!-- %.*s -->\n",
446 (int) token->data.comment.len,
447 token->data.comment.ptr);
449 case HUBBUB_TOKEN_CHARACTER:
450 p += snprintf(p, end - p, "%.*s", (int) token->data.character.len,
451 token->data.character.ptr);
453 case HUBBUB_TOKEN_EOF:
454 p += snprintf(p, end - p, "\n");
458 if (user_callback_handle_rxflow(r->wsi->protocol->callback,
459 r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
460 r->wsi->user_space, start, p - start))
467 * lws_client_connect_via_info() - Connect to another websocket server
468 * @i:pointer to lws_client_connect_info struct
470 * This function creates a connection to a remote server
474 LWS_VISIBLE struct lws *
475 lws_client_connect_via_info(struct lws_client_connect_info *i)
478 int v = SPEC_LATEST_SUPPORTED;
480 if (i->context->requested_kill)
483 wsi = lws_zalloc(sizeof(struct lws));
487 wsi->context = i->context;
488 /* assert the mode and union status (hdr) clearly */
489 lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
490 wsi->sock = LWS_SOCK_INVALID;
492 /* 1) fill up the wsi with stuff from the connect_info as far as it
493 * can go. It's because not only is our connection async, we might
494 * not even be able to get ahold of an ah at this point.
497 /* -1 means just use latest supported */
498 if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
499 v = i->ietf_version_or_minus_one;
501 wsi->ietf_spec_revision = v;
502 wsi->user_space = NULL;
503 wsi->state = LWSS_CLIENT_UNCONNECTED;
504 wsi->protocol = NULL;
505 wsi->pending_timeout = NO_PENDING_TIMEOUT;
506 wsi->position_in_fds_table = -1;
507 wsi->u.hdr.c_port = i->port;
508 wsi->vhost = i->vhost;
510 wsi->vhost = i->context->vhost_list;
512 wsi->protocol = &wsi->vhost->protocols[0];
513 if (wsi && !wsi->user_space && i->userdata) {
514 wsi->user_space_externally_allocated = 1;
515 wsi->user_space = i->userdata;
517 /* if we stay in http, we can assign the user space now,
518 * otherwise do it after the protocol negotiated
521 if (lws_ensure_user_space(wsi))
524 #ifdef LWS_OPENSSL_SUPPORT
525 wsi->use_ssl = i->ssl_connection;
527 if (i->ssl_connection) {
528 lwsl_err("libwebsockets not configured for ssl\n");
533 /* 2) stash the things from connect_info that we can't process without
534 * an ah. Because if no ah, we will go on the ah waiting list and
535 * process those things later (after the connect_info and maybe the
536 * things pointed to have gone out of scope.
539 wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
540 if (!wsi->u.hdr.stash) {
541 lwsl_err("%s: OOM\n", __func__);
545 wsi->u.hdr.stash->origin[0] = '\0';
546 wsi->u.hdr.stash->protocol[0] = '\0';
547 wsi->u.hdr.stash->method[0] = '\0';
549 strncpy(wsi->u.hdr.stash->address, i->address,
550 sizeof(wsi->u.hdr.stash->address) - 1);
551 strncpy(wsi->u.hdr.stash->path, i->path,
552 sizeof(wsi->u.hdr.stash->path) - 1);
553 strncpy(wsi->u.hdr.stash->host, i->host,
554 sizeof(wsi->u.hdr.stash->host) - 1);
556 strncpy(wsi->u.hdr.stash->origin, i->origin,
557 sizeof(wsi->u.hdr.stash->origin) - 1);
559 strncpy(wsi->u.hdr.stash->protocol, i->protocol,
560 sizeof(wsi->u.hdr.stash->protocol) - 1);
562 strncpy(wsi->u.hdr.stash->method, i->method,
563 sizeof(wsi->u.hdr.stash->method) - 1);
565 wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
566 wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
567 wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
568 wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
569 wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
570 wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
572 /* if we went on the waiting list, no probs just return the wsi
573 * when we get the ah, now or later, he will call
574 * lws_client_connect_via_info2() below.
576 if (lws_header_table_attach(wsi, 0) < 0)
580 lwsl_info("%s: created child %p of parent %p\n", __func__,
582 wsi->parent = i->parent_wsi;
583 wsi->sibling_list = i->parent_wsi->child_list;
584 i->parent_wsi->child_list = wsi;
586 #ifdef LWS_WITH_HTTP_PROXY
587 if (i->uri_replace_to)
588 wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
602 lws_client_connect_via_info2(struct lws *wsi)
604 struct client_info_stash *stash = wsi->u.hdr.stash;
610 * we're not necessarily in a position to action these right away,
611 * stash them... we only need during connect phase so u.hdr is fine
613 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
617 /* these only need u.hdr lifetime as well */
619 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
622 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
625 if (stash->origin[0])
626 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
630 * this is a list of protocols we tell the server we're okay with
631 * stash it for later when we compare server response with it
633 if (stash->protocol[0])
634 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
637 if (stash->method[0])
638 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
642 lws_free_set_NULL(wsi->u.hdr.stash);
645 * Check with each extension if it is able to route and proxy this
646 * connection for us. For example, an extension like x-google-mux
647 * can handle this and then we don't need an actual socket for this
651 if (lws_ext_cb_all_exts(wsi->context, wsi,
652 LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
653 (void *)stash->address,
654 wsi->u.hdr.c_port) > 0) {
655 lwsl_client("lws_client_connect: ext handling conn\n");
658 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
661 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
664 lwsl_client("lws_client_connect: direct conn\n");
665 wsi->context->count_wsi_allocated++;
667 return lws_client_connect_2(wsi);
670 lws_free_set_NULL(wsi->u.hdr.stash);
677 * lws_client_connect_extended() - Connect to another websocket server
678 * DEPRECATED use lws_client_connect_via_info
679 * @context: Websocket context
680 * @address: Remote server address, eg, "myserver.com"
681 * @port: Port to connect to on the remote server, eg, 80
682 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
684 * @path: Websocket path on server
685 * @host: Hostname on server
686 * @origin: Socket origin name
687 * @protocol: Comma-separated list of protocols being asked for from
688 * the server, or just one. The server will pick the one it
690 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
691 * protocol supported, or the specific protocol ordinal
692 * @userdata: Pre-allocated user data
694 * This function creates a connection to a remote server
697 LWS_VISIBLE struct lws *
698 lws_client_connect_extended(struct lws_context *context, const char *address,
699 int port, int ssl_connection, const char *path,
700 const char *host, const char *origin,
701 const char *protocol, int ietf_version_or_minus_one,
704 struct lws_client_connect_info i;
706 memset(&i, 0, sizeof(i));
711 i.ssl_connection = ssl_connection;
715 i.protocol = protocol;
716 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
717 i.userdata = userdata;
719 return lws_client_connect_via_info(&i);
722 * lws_client_connect_info() - Connect to another websocket server
723 * DEPRECATED use lws_client_connect_via_info
724 * @context: Websocket context
725 * @address: Remote server address, eg, "myserver.com"
726 * @port: Port to connect to on the remote server, eg, 80
727 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
729 * @path: Websocket path on server
730 * @host: Hostname on server
731 * @origin: Socket origin name
732 * @protocol: Comma-separated list of protocols being asked for from
733 * the server, or just one. The server will pick the one it
734 * likes best. If you don't want to specify a protocol, which is
735 * legal, use NULL here.
736 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
737 * protocol supported, or the specific protocol ordinal
739 * This function creates a connection to a remote server
743 LWS_VISIBLE struct lws *
744 lws_client_connect(struct lws_context *context, const char *address,
745 int port, int ssl_connection, const char *path,
746 const char *host, const char *origin,
747 const char *protocol, int ietf_version_or_minus_one)
749 struct lws_client_connect_info i;
751 memset(&i, 0, sizeof(i));
756 i.ssl_connection = ssl_connection;
760 i.protocol = protocol;
761 i.ietf_version_or_minus_one = ietf_version_or_minus_one;
764 return lws_client_connect_via_info(&i);