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 sockaddr_in server_addr4;
13 struct sockaddr_in client_addr4;
14 struct lws_pollfd pfd;
19 lwsl_client("%s\n", __func__);
23 if (context->http_proxy_port) {
24 plen = sprintf((char *)context->serv_buf,
25 "CONNECT %s:%u HTTP/1.0\x0d\x0a"
26 "User-agent: libwebsockets\x0d\x0a",
27 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
28 wsi->u.hdr.ah->c_port);
30 if (context->proxy_basic_auth_token[0])
31 plen += sprintf((char *)context->serv_buf + plen,
32 "Proxy-authorization: basic %s\x0d\x0a",
33 context->proxy_basic_auth_token);
35 plen += sprintf((char *)context->serv_buf + plen,
38 ads = context->http_proxy_address;
41 if (LWS_IPV6_ENABLED(context)) {
42 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
43 server_addr6.sin6_port = htons(context->http_proxy_port);
46 server_addr4.sin_port = htons(context->http_proxy_port);
49 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
51 if (LWS_IPV6_ENABLED(context)) {
52 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
53 server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
56 server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
60 * prepare the actual connection (to the proxy, if any)
62 lwsl_client("%s: address %s\n", __func__, ads);
65 if (LWS_IPV6_ENABLED(context)) {
66 memset(&hints, 0, sizeof(struct addrinfo));
67 #if !defined(__ANDROID__)
68 hints.ai_family = AF_INET6;
69 hints.ai_flags = AI_V4MAPPED;
71 n = getaddrinfo(ads, NULL, &hints, &result);
74 lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
76 lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
81 server_addr6.sin6_family = AF_INET6;
82 switch (result->ai_family) {
83 #if defined(__ANDROID__)
85 /* map IPv4 to IPv6 */
86 bzero((char *)&server_addr6.sin6_addr,
87 sizeof(struct in6_addr));
88 server_addr6.sin6_addr.s6_addr[10] = 0xff;
89 server_addr6.sin6_addr.s6_addr[11] = 0xff;
90 memcpy(&server_addr6.sin6_addr.s6_addr[12],
91 &((struct sockaddr_in *)result->ai_addr)->sin_addr,
92 sizeof(struct in_addr));
96 memcpy(&server_addr6.sin6_addr,
97 &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
98 sizeof(struct in6_addr));
101 lwsl_err("Unknown address family\n");
102 freeaddrinfo(result);
106 freeaddrinfo(result);
110 struct addrinfo ai, *res, *result;
113 memset (&ai, 0, sizeof ai);
114 ai.ai_family = PF_UNSPEC;
115 ai.ai_socktype = SOCK_STREAM;
116 ai.ai_flags = AI_CANONNAME;
118 if (getaddrinfo(ads, NULL, &ai, &result))
123 switch (res->ai_family) {
125 p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
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(context, 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 if (insert_wsi_socket_into_fds(context, wsi)) {
167 compatible_close(wsi->sock);
172 * past here, we can't simply free the structs as error
173 * handling as oom4 does. We have to run the whole close flow.
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))
237 lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
242 if (LWS_ERRNO != LWS_EISCONN) {
243 lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
248 lwsl_client("connected\n");
250 /* we are connected to server, or proxy */
252 if (context->http_proxy_port) {
255 * OK from now on we talk via the proxy, so connect to that
257 * (will overwrite existing pointer,
258 * leaving old string/frag there but unreferenced)
260 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
261 context->http_proxy_address))
263 wsi->u.hdr.ah->c_port = context->http_proxy_port;
265 n = send(wsi->sock, (char *)context->serv_buf, plen,
268 lwsl_debug("ERROR writing to proxy socket\n");
272 lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
275 wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
281 * provoke service to issue the handshake directly
282 * we need to do it this way because in the proxy case, this is the
283 * next state and executed only if and when we get a good proxy
284 * response inside the state machine... but notice in SSL case this
285 * may not have sent anything yet with 0 return, and won't until some
286 * many retries from main loop. To stop that becoming endless,
287 * cover with a timeout.
290 lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
293 wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
295 pfd.revents = LWS_POLLIN;
297 n = lws_service_fd(context, &pfd);
300 if (n) /* returns 1 on failure after closing wsi */
306 lws_free_header_table(wsi);
312 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
318 * lws_client_connect() - Connect to another websocket server
319 * @context: Websocket context
320 * @address: Remote server address, eg, "myserver.com"
321 * @port: Port to connect to on the remote server, eg, 80
322 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
324 * @path: Websocket path on server
325 * @host: Hostname on server
326 * @origin: Socket origin name
327 * @protocol: Comma-separated list of protocols being asked for from
328 * the server, or just one. The server will pick the one it
329 * likes best. If you don't want to specify a protocol, which is
330 * legal, use NULL here.
331 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
332 * protocol supported, or the specific protocol ordinal
334 * This function creates a connection to a remote server
337 LWS_VISIBLE struct lws *
338 lws_client_connect(struct lws_context *context, const char *address,
339 int port, int ssl_connection, const char *path,
340 const char *host, const char *origin,
341 const char *protocol, int ietf_version_or_minus_one)
345 wsi = lws_zalloc(sizeof(struct lws));
349 wsi->context = context;
350 wsi->sock = LWS_SOCK_INVALID;
352 /* -1 means just use latest supported */
354 if (ietf_version_or_minus_one == -1)
355 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
357 wsi->ietf_spec_revision = ietf_version_or_minus_one;
358 wsi->user_space = NULL;
359 wsi->state = LWSS_CLIENT_UNCONNECTED;
360 wsi->protocol = NULL;
361 wsi->pending_timeout = NO_PENDING_TIMEOUT;
363 #ifdef LWS_OPENSSL_SUPPORT
364 wsi->use_ssl = ssl_connection;
366 if (ssl_connection) {
367 lwsl_err("libwebsockets not configured for ssl\n");
372 if (lws_allocate_header_table(wsi))
376 * we're not necessarily in a position to action these right away,
377 * stash them... we only need during connect phase so u.hdr is fine
379 wsi->u.hdr.ah->c_port = port;
380 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
383 /* these only need u.hdr lifetime as well */
385 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
388 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
392 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, origin))
395 * this is a list of protocols we tell the server we're okay with
396 * stash it for later when we compare server response with it
399 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
403 wsi->protocol = &context->protocols[0];
406 * Check with each extension if it is able to route and proxy this
407 * connection for us. For example, an extension like x-google-mux
408 * can handle this and then we don't need an actual socket for this
412 if (lws_ext_cb_all_exts(context, wsi,
413 LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
414 (void *)address, port) > 0) {
415 lwsl_client("lws_client_connect: ext handling conn\n");
418 PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
421 wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
424 lwsl_client("lws_client_connect: direct conn\n");
426 return lws_client_connect_2(wsi);
429 lws_free_header_table(wsi);
438 * lws_client_connect_extended() - Connect to another websocket server
439 * @context: Websocket context
440 * @address: Remote server address, eg, "myserver.com"
441 * @port: Port to connect to on the remote server, eg, 80
442 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
444 * @path: Websocket path on server
445 * @host: Hostname on server
446 * @origin: Socket origin name
447 * @protocol: Comma-separated list of protocols being asked for from
448 * the server, or just one. The server will pick the one it
450 * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
451 * protocol supported, or the specific protocol ordinal
452 * @userdata: Pre-allocated user data
454 * This function creates a connection to a remote server
457 LWS_VISIBLE struct lws *
458 lws_client_connect_extended(struct lws_context *context, const char *address,
459 int port, int ssl_connection, const char *path,
460 const char *host, const char *origin,
461 const char *protocol, int ietf_version_or_minus_one,
466 wsi = lws_client_connect(context, address, port, ssl_connection, path,
467 host, origin, protocol,
468 ietf_version_or_minus_one);
470 if (wsi && !wsi->user_space && userdata) {
471 wsi->user_space_externally_allocated = 1;
472 wsi->user_space = userdata ;