add ipv6 support
[platform/upstream/libwebsockets.git] / lib / client-handshake.c
1 #include "private-libwebsockets.h"
2
3 struct libwebsocket *libwebsocket_client_connect_2(
4         struct libwebsocket_context *context,
5         struct libwebsocket *wsi
6 ) {
7         struct pollfd pfd;
8 #ifdef LWS_WITH_IPV6
9         struct sockaddr_in6 server_addr6;
10         struct sockaddr_in6 client_addr6;
11         struct addrinfo hints, *result;
12 #endif
13         struct sockaddr_in server_addr4;
14         struct sockaddr_in client_addr4;
15         struct hostent *server_hostent;
16
17         struct sockaddr *v;
18         int n;
19         int plen = 0;
20         const char *ads;
21
22        lwsl_client("libwebsocket_client_connect_2\n");
23
24         /*
25          * proxy?
26          */
27
28         if (context->http_proxy_port) {
29                 plen = sprintf((char *)context->service_buffer,
30                         "CONNECT %s:%u HTTP/1.0\x0d\x0a"
31                         "User-agent: libwebsockets\x0d\x0a"
32 /*Proxy-authorization: basic aGVsbG86d29ybGQ= */
33                         "\x0d\x0a",
34                         lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
35                         wsi->u.hdr.ah->c_port);
36                 ads = context->http_proxy_address;
37
38 #ifdef LWS_WITH_IPV6
39                 if (LWS_IPV6_ENABLED(context))
40                         server_addr6.sin6_port = htons(context->http_proxy_port);
41                 else
42 #endif
43                         server_addr4.sin_port = htons(context->http_proxy_port);
44
45         } else {
46                 ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
47 #ifdef LWS_WITH_IPV6
48                 if (LWS_IPV6_ENABLED(context))
49                         server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
50                 else
51 #endif
52                         server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
53         }
54
55         /*
56          * prepare the actual connection (to the proxy, if any)
57          */
58        lwsl_client("libwebsocket_client_connect_2: address %s\n", ads);
59
60 #ifdef LWS_WITH_IPV6
61         if (LWS_IPV6_ENABLED(context)) {
62                 memset(&hints, 0, sizeof(struct addrinfo));
63                 n = getaddrinfo(ads, NULL, &hints, &result);
64                 if (n) {
65                         lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
66                         goto oom4;
67                 }
68
69                 server_addr6.sin6_family = AF_INET6;
70                 switch (result->ai_family) {
71                 case AF_INET:
72                         /* map IPv4 to IPv6 */
73                         bzero((char *)&server_addr6.sin6_addr,
74                                                 sizeof(struct in6_addr));
75                         server_addr6.sin6_addr.s6_addr16[5] = 0xffff;
76                         bcopy(&((struct sockaddr_in *)result->ai_addr)->sin_addr,
77                                 &server_addr6.sin6_addr.s6_addr16[6],
78                                                         sizeof(struct in_addr));
79                         break;
80                 case AF_INET6:
81                         memcpy(&server_addr6.sin6_addr,
82                           &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
83                                                 sizeof(struct in6_addr));
84                         break;
85                 default:
86                         lwsl_err("Unknown address family\n");
87                         freeaddrinfo(result);
88                         goto oom4;
89                 }
90
91                 freeaddrinfo(result);
92         } else
93 #endif
94         {
95                 server_hostent = gethostbyname(ads);
96                 if (!server_hostent) {
97                         lwsl_err("Unable to get host name from %s\n", ads);
98                         goto oom4;
99                 }
100
101                 server_addr4.sin_family = AF_INET;
102                 server_addr4.sin_addr =
103                                 *((struct in_addr *)server_hostent->h_addr);
104                 bzero(&server_addr4.sin_zero, 8);
105         }
106
107         if (wsi->sock < 0) {
108
109 #ifdef LWS_WITH_IPV6
110                 if (LWS_IPV6_ENABLED(context))
111                         wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
112                 else
113 #endif
114                         wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
115
116                 if (wsi->sock < 0) {
117                         lwsl_warn("Unable to open socket\n");
118                         goto oom4;
119                 }
120
121                 if (lws_set_socket_options(context, wsi->sock)) {
122                         lwsl_err("Failed to set wsi socket options\n");
123                         compatible_close(wsi->sock);
124                         goto oom4;
125                 }
126
127                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT;
128
129                 insert_wsi_socket_into_fds(context, wsi);
130
131                 libwebsocket_set_timeout(wsi,
132                         PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
133                                                               AWAITING_TIMEOUT);
134 #ifdef LWS_WITH_IPV6
135                 if (LWS_IPV6_ENABLED(context)) {
136                         v = (struct sockaddr *)&client_addr6;
137                         n = sizeof(client_addr6);
138                         bzero((char *)v, n);
139                         client_addr6.sin6_family = AF_INET6;
140                 } else
141 #endif
142                 {
143                         v = (struct sockaddr *)&client_addr4;
144                         n = sizeof(client_addr4);
145                         bzero((char *)v, n);
146                         client_addr4.sin_family = AF_INET;
147                 }
148
149                 if (context->iface) {
150                         if (interface_to_sa(context, context->iface,
151                                         (struct sockaddr_in *)v, n) < 0) {
152                                 lwsl_err("Unable to find interface %s\n",
153                                                                 context->iface);
154                                 compatible_close(wsi->sock);
155                                 goto failed;
156                         }
157
158                         if (bind(wsi->sock, v, n) < 0) {
159                                 lwsl_err("Error binding to interface %s",
160                                                                 context->iface);
161                                 compatible_close(wsi->sock);
162                                 goto failed;
163                         }
164                 }
165         }
166
167 #ifdef LWS_WITH_IPV6
168         if (LWS_IPV6_ENABLED(context)) {
169                 v = (struct sockaddr *)&server_addr6;
170                 n = sizeof(struct sockaddr_in6);
171         } else
172 #endif
173         {
174                 v = (struct sockaddr *)&server_addr4;
175                 n = sizeof(struct sockaddr);
176         }
177
178         if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
179
180                 if (LWS_ERRNO == LWS_EALREADY || LWS_ERRNO == LWS_EINPROGRESS) {
181                         lwsl_client("nonblocking connect retry\n");
182
183                         /*
184                          * must do specifically a POLLOUT poll to hear
185                          * about the connect completion
186                          */
187                         lws_change_pollfd(wsi, 0, POLLOUT);
188
189                         return wsi;
190                 }
191
192                 if (LWS_ERRNO != LWS_EISCONN) {
193                         lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
194                         goto failed;
195                 }
196         }
197
198         lwsl_client("connected\n");
199
200         /* we are connected to server, or proxy */
201
202         if (context->http_proxy_port) {
203
204                 /* OK from now on we talk via the proxy, so connect to that */
205
206                 /*
207                  * (will overwrite existing pointer,
208                  * leaving old string/frag there but unreferenced)
209                  */
210                 if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
211                                                    context->http_proxy_address))
212                         goto failed;
213                 wsi->u.hdr.ah->c_port = context->http_proxy_port;
214
215                 n = send(wsi->sock, context->service_buffer, plen, MSG_NOSIGNAL);
216                 if (n < 0) {
217                         lwsl_debug("ERROR writing to proxy socket\n");
218                         goto failed;
219                 }
220
221                 libwebsocket_set_timeout(wsi,
222                         PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
223                                                               AWAITING_TIMEOUT);
224
225                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
226
227                 return wsi;
228         }
229
230         /*
231          * provoke service to issue the handshake directly
232          * we need to do it this way because in the proxy case, this is the
233          * next state and executed only if and when we get a good proxy
234          * response inside the state machine... but notice in SSL case this
235          * may not have sent anything yet with 0 return, and won't until some
236          * many retries from main loop.  To stop that becoming endless,
237          * cover with a timeout.
238          */
239
240         libwebsocket_set_timeout(wsi,
241                 PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
242
243         wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
244         pfd.fd = wsi->sock;
245         pfd.revents = POLLIN;
246
247         n = libwebsocket_service_fd(context, &pfd);
248
249         if (n < 0)
250                 goto failed;
251
252         if (n) /* returns 1 on failure after closing wsi */
253                 return NULL;
254
255         return wsi;
256
257 oom4:
258         free(wsi->u.hdr.ah);
259         free(wsi);
260         return NULL;
261
262 failed:
263         libwebsocket_close_and_free_session(context, wsi,
264                                                      LWS_CLOSE_STATUS_NOSTATUS);
265         return NULL;
266 }
267
268 /**
269  * libwebsocket_client_connect() - Connect to another websocket server
270  * @context:    Websocket context
271  * @address:    Remote server address, eg, "myserver.com"
272  * @port:       Port to connect to on the remote server, eg, 80
273  * @ssl_connection:     0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
274  *                      signed certs
275  * @path:       Websocket path on server
276  * @host:       Hostname on server
277  * @origin:     Socket origin name
278  * @protocol:   Comma-separated list of protocols being asked for from
279  *              the server, or just one.  The server will pick the one it
280  *              likes best.
281  * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
282  *              protocol supported, or the specific protocol ordinal
283  *
284  *      This function creates a connection to a remote server
285  */
286
287 LWS_VISIBLE struct libwebsocket *
288 libwebsocket_client_connect(struct libwebsocket_context *context,
289                               const char *address,
290                               int port,
291                               int ssl_connection,
292                               const char *path,
293                               const char *host,
294                               const char *origin,
295                               const char *protocol,
296                               int ietf_version_or_minus_one)
297 {
298         struct libwebsocket *wsi;
299 #ifndef LWS_NO_EXTENSIONS
300         int n;
301         int m;
302         struct libwebsocket_extension *ext;
303         int handled;
304 #endif
305
306 #ifndef LWS_OPENSSL_SUPPORT
307         if (ssl_connection) {
308                 lwsl_err("libwebsockets not configured for ssl\n");
309                 return NULL;
310         }
311 #endif
312
313         wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
314         if (wsi == NULL)
315                 goto bail;
316
317         memset(wsi, 0, sizeof(*wsi));
318         wsi->sock = -1;
319
320         /* -1 means just use latest supported */
321
322         if (ietf_version_or_minus_one == -1)
323                 ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
324
325         wsi->ietf_spec_revision = ietf_version_or_minus_one;
326         wsi->user_space = NULL;
327         wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
328         wsi->protocol = NULL;
329         wsi->pending_timeout = NO_PENDING_TIMEOUT;
330 #ifndef LWS_NO_EXTENSIONS
331         wsi->count_active_extensions = 0;
332 #endif
333 #ifdef LWS_OPENSSL_SUPPORT
334         wsi->use_ssl = ssl_connection;
335 #endif
336
337         if (lws_allocate_header_table(wsi))
338                 goto bail;
339
340         /*
341          * we're not necessarily in a position to action these right away,
342          * stash them... we only need during connect phase so u.hdr is fine
343          */
344         wsi->u.hdr.ah->c_port = port;
345         if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
346                 goto bail1;
347
348         /* these only need u.hdr lifetime as well */
349
350         if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
351                 goto bail1;
352
353         if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
354                 goto bail1;
355
356         if (origin)
357                 if (lws_hdr_simple_create(wsi,
358                                 _WSI_TOKEN_CLIENT_ORIGIN, origin))
359                         goto bail1;
360         /*
361          * this is a list of protocols we tell the server we're okay with
362          * stash it for later when we compare server response with it
363          */
364         if (protocol)
365                 if (lws_hdr_simple_create(wsi,
366                                 _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol))
367                         goto bail1;
368
369         wsi->protocol = &context->protocols[0];
370
371 #ifndef LWS_NO_EXTENSIONS
372         /*
373          * Check with each extension if it is able to route and proxy this
374          * connection for us.  For example, an extension like x-google-mux
375          * can handle this and then we don't need an actual socket for this
376          * connection.
377          */
378
379         handled = 0;
380         ext = context->extensions;
381         n = 0;
382
383         while (ext && ext->callback && !handled) {
384                 m = ext->callback(context, ext, wsi,
385                         LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
386                                  (void *)(long)n, (void *)address, port);
387                 if (m)
388                         handled = 1;
389
390                 ext++;
391                 n++;
392         }
393
394         if (handled) {
395                 lwsl_client("libwebsocket_client_connect: ext handling conn\n");
396
397                 libwebsocket_set_timeout(wsi,
398                         PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
399                                                               AWAITING_TIMEOUT);
400
401                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
402                 return wsi;
403         }
404 #endif
405         lwsl_client("libwebsocket_client_connect: direct conn\n");
406
407        return libwebsocket_client_connect_2(context, wsi);
408
409 bail1:
410         free(wsi->u.hdr.ah);
411 bail:
412         free(wsi);
413
414         return NULL;
415 }
416
417
418 /**
419  * libwebsocket_client_connect_extended() - Connect to another websocket server
420  * @context:    Websocket context
421  * @address:    Remote server address, eg, "myserver.com"
422  * @port:       Port to connect to on the remote server, eg, 80
423  * @ssl_connection:     0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
424  *                      signed certs
425  * @path:       Websocket path on server
426  * @host:       Hostname on server
427  * @origin:     Socket origin name
428  * @protocol:   Comma-separated list of protocols being asked for from
429  *              the server, or just one.  The server will pick the one it
430  *              likes best.
431  * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
432  *              protocol supported, or the specific protocol ordinal
433  * @userdata: Pre-allocated user data
434  *
435  *      This function creates a connection to a remote server
436  */
437
438 LWS_VISIBLE struct libwebsocket *
439 libwebsocket_client_connect_extended(struct libwebsocket_context *context,
440                               const char *address,
441                               int port,
442                               int ssl_connection,
443                               const char *path,
444                               const char *host,
445                               const char *origin,
446                               const char *protocol,
447                               int ietf_version_or_minus_one,
448                               void *userdata)
449 {
450         struct libwebsocket *ws =
451                 libwebsocket_client_connect(context, address, port,
452                         ssl_connection, path, host, origin, protocol,
453                                                      ietf_version_or_minus_one);
454
455         if (ws && !ws->user_space && userdata)
456                 ws->user_space = userdata ;
457
458         return ws ;
459 }