fa0f5a5f49f720c9e7341734a3834f810ffa63fd
[profile/ivi/libwebsockets.git] / lib / client-handshake.c
1 #include "private-libwebsockets.h"
2 #include <netdb.h>
3
4
5 /*
6  * In-place str to lower case
7  */
8
9 void
10 strtolower(char *s)
11 {
12         while (*s) {
13                 *s = tolower(*s);
14                 s++;
15         }
16 }
17
18 void
19 libwebsocket_client_close(struct libwebsocket *wsi)
20 {
21         int n = wsi->state;
22         struct libwebsocket_context *clients;
23         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 +
24                                                   LWS_SEND_BUFFER_POST_PADDING];
25
26         if (n == WSI_STATE_DEAD_SOCKET)
27                 return;
28
29         /*
30          * signal we are closing, libsocket_write will
31          * add any necessary version-specific stuff.  If the write fails,
32          * no worries we are closing anyway.  If we didn't initiate this
33          * close, then our state has been changed to
34          * WSI_STATE_RETURNED_CLOSE_ALREADY and we can skip this
35          */
36
37         if (n == WSI_STATE_ESTABLISHED)
38                 libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 0,
39                                                                LWS_WRITE_CLOSE);
40         /* mark the WSI as dead and let the callback know */
41
42         wsi->state = WSI_STATE_DEAD_SOCKET;
43
44         if (wsi->protocol) {
45                 if (wsi->protocol->callback && n == WSI_STATE_ESTABLISHED)
46                         wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED,
47                                                       wsi->user_space, NULL, 0);
48
49                 /* remove it from the client polling list */
50                 clients = wsi->protocol->owning_server;
51                 if (clients)
52                         for (n = 0; n < clients->fds_count; n++) {
53                                 if (clients->wsi[n] != wsi)
54                                         continue;
55                                 while (n < clients->fds_count - 1) {
56                                         clients->fds[n] = clients->fds[n + 1];
57                                         clients->wsi[n] = clients->wsi[n + 1];
58                                         n++;
59                                 }
60                                 /* we only have to deal with one */
61                                 n = clients->fds_count;
62                         }
63
64         }
65
66         /* clean out any parsing allocations */
67
68         for (n = 0; n < WSI_TOKEN_COUNT; n++)
69                 if (wsi->utf8_token[n].token)
70                         free(wsi->utf8_token[n].token);
71
72         /* shut down reasonably cleanly */
73
74 #ifdef LWS_OPENSSL_SUPPORT
75         if (wsi->ssl) {
76                 n = SSL_get_fd(wsi->ssl);
77                 SSL_shutdown(wsi->ssl);
78                 close(n);
79                 SSL_free(wsi->ssl);
80         } else {
81 #endif
82                 shutdown(wsi->sock, SHUT_RDWR);
83                 close(wsi->sock);
84 #ifdef LWS_OPENSSL_SUPPORT
85         }
86 #endif
87 }
88
89
90 /**
91  * libwebsocket_client_connect() - Connect to another websocket server
92  * @this:       Websocket context
93  * @address:    Remote server address, eg, "myserver.com"
94  * @port:       Port to connect to on the remote server, eg, 80
95  * @ssl_connection:     0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
96  *                      signed certs
97  * @path:       Websocket path on server
98  * @host:       Hostname on server
99  * @origin:     Socket origin name
100  * @protocol:   Comma-separated list of protocols being asked for from
101  *              the server, or just one.  The server will pick the one it
102  *              likes best.
103  * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
104  *              protocol supported, or the specific protocol ordinal
105  *
106  *      This function creates a connection to a remote server
107  */
108
109 struct libwebsocket *
110 libwebsocket_client_connect(struct libwebsocket_context *this,
111                               const char *address,
112                               int port,
113                               int ssl_connection,
114                               const char *path,
115                               const char *host,
116                               const char *origin,
117                               const char *protocol,
118                               int ietf_version_or_minus_one)
119 {
120         struct hostent *server_hostent;
121         struct sockaddr_in server_addr;
122         char buf[150];
123         char key_b64[150];
124         char hash[20];
125         int fd;
126         struct pollfd pfd;
127         static const char magic_websocket_guid[] =
128                                          "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
129         static const char magic_websocket_04_masking_guid[] =
130                                          "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
131         char pkt[1024];
132         char *p = &pkt[0];
133         const char *pc;
134         int len;
135         int okay = 0;
136         struct libwebsocket *wsi;
137         int n;
138         int plen = 0;
139 #ifdef LWS_OPENSSL_SUPPORT
140         char ssl_err_buf[512];
141 #else
142         if (ssl_connection) {
143                 fprintf(stderr, "libwebsockets not configured for ssl\n");
144                 return NULL;
145         }
146 #endif
147
148         wsi = malloc(sizeof(struct libwebsocket));
149         if (wsi == NULL) {
150                 fprintf(stderr, "Out of memory allocing new connection\n");
151                 return NULL;
152         }
153
154         this->wsi[this->fds_count] = wsi;
155
156         /* -1 means just use latest supported */
157
158         if (ietf_version_or_minus_one == -1)
159                 ietf_version_or_minus_one = 5;
160
161         wsi->ietf_spec_revision = ietf_version_or_minus_one;
162         wsi->name_buffer_pos = 0;
163         wsi->user_space = NULL;
164         wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
165         wsi->pings_vs_pongs = 0;
166         wsi->protocol = NULL;
167
168         /* set up appropriate masking */
169
170         wsi->xor_mask = xor_no_mask;
171
172         switch (wsi->ietf_spec_revision) {
173         case 4:
174                 wsi->xor_mask = xor_mask_04;
175                 break;
176         case 5:
177                 wsi->xor_mask = xor_mask_05;
178                 break;
179         default:
180                 fprintf(stderr,
181                         "Client ietf version %d not supported\n",
182                                                        wsi->ietf_spec_revision);
183                 return NULL;
184         }
185
186         /* force no mask if he asks for that though */
187
188         if (this->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
189                 wsi->xor_mask = xor_no_mask;
190
191         for (n = 0; n < WSI_TOKEN_COUNT; n++) {
192                 wsi->utf8_token[n].token = NULL;
193                 wsi->utf8_token[n].token_len = 0;
194         }
195
196         /*
197          * proxy?
198          */
199
200         if (this->http_proxy_port) {
201                 plen = sprintf(pkt, "CONNECT %s:%u HTTP/1.0\x0d\x0a"
202                         "User-agent: libwebsockets\x0d\x0a"
203 /*Proxy-authorization: basic aGVsbG86d29ybGQ= */
204                         "\x0d\x0a", address, port);
205
206                 /* OK from now on we talk via the proxy */
207
208                 address = this->http_proxy_address;
209                 port = this->http_proxy_port;
210         }
211
212         /*
213          * prepare the actual connection (to the proxy, if any)
214          */
215
216         server_hostent = gethostbyname(address);
217         if (server_hostent == NULL) {
218                 fprintf(stderr, "Unable to get host name from %s\n", address);
219                 goto bail1;
220         }
221
222         wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
223
224         if (wsi->sock < 0) {
225                 fprintf(stderr, "Unable to open socket\n");
226                 goto bail1;
227         }
228
229
230         server_addr.sin_family = AF_INET;
231         server_addr.sin_port = htons(port);
232         server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
233         bzero(&server_addr.sin_zero, 8);
234
235         if (connect(wsi->sock, (struct sockaddr *)&server_addr,
236                                               sizeof(struct sockaddr)) == -1)  {
237                 fprintf(stderr, "Connect failed\n");
238                 goto bail1;
239         }
240
241         /* we are connected to server, or proxy */
242
243         if (this->http_proxy_port) {
244
245                 n = send(wsi->sock, pkt, plen, 0);
246                 if (n < 0) {
247                         close(wsi->sock);
248                         fprintf(stderr, "ERROR writing to proxy socket\n");
249                         goto bail1;
250                 }
251
252                 pfd.fd = wsi->sock;
253                 pfd.events = POLLIN;
254                 pfd.revents = 0;
255
256                 n = poll(&pfd, 1, 5000);
257                 if (n <= 0) {
258                         close(wsi->sock);
259                         fprintf(stderr, "libwebsocket_client_handshake "
260                                         "timeout on proxy response");
261                         goto bail1;
262                 }
263
264                 n = recv(wsi->sock, pkt, sizeof pkt, 0);
265                 if (n < 0) {
266                         close(wsi->sock);
267                         fprintf(stderr, "ERROR reading from proxy socket\n");
268                         goto bail1;
269                 }
270
271                 pkt[13] = '\0';
272                 if (strcmp(pkt, "HTTP/1.0 200 ") != 0) {
273                         close(wsi->sock);
274                         fprintf(stderr, "ERROR from proxy: %s\n", pkt);
275                         goto bail1;
276                 }
277
278                 /* we can just start sending to proxy */
279         }
280
281 #ifdef LWS_OPENSSL_SUPPORT
282         if (ssl_connection) {
283
284                 wsi->ssl = SSL_new(this->ssl_client_ctx);
285                 wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
286                 SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
287
288                 if (SSL_connect(wsi->ssl) <= 0) {
289                         fprintf(stderr, "SSL connect error %s\n",
290                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
291                         goto bail1;
292                 }
293
294                 n = SSL_get_verify_result(wsi->ssl);
295                 if (n != X509_V_OK) {
296                         if (n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
297                                                           ssl_connection != 2) {
298
299                                 fprintf(stderr, "server's cert didn't "
300                                                            "look good %d\n", n);
301                                 goto bail2;
302                         }
303                 }
304         } else {
305                 wsi->ssl = NULL;
306 #endif
307
308
309 #ifdef LWS_OPENSSL_SUPPORT
310         }
311 #endif
312
313         /*
314          * create the random key
315          */
316
317         fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
318         if (fd < 1) {
319                 fprintf(stderr, "Unable to open random device %s\n",
320                                                         SYSTEM_RANDOM_FILEPATH);
321                 goto bail2;
322         }
323         n = read(fd, hash, 16);
324         if (n != 16) {
325                 fprintf(stderr, "Unable to read from random device %s\n",
326                                                         SYSTEM_RANDOM_FILEPATH);
327                 close(fd);
328                 goto bail2;
329         }
330         close(fd);
331
332         lws_b64_encode_string(hash, 16, key_b64, sizeof key_b64);
333
334         /*
335          * 04 example client handshake
336          *
337          * GET /chat HTTP/1.1
338          * Host: server.example.com
339          * Upgrade: websocket
340          * Connection: Upgrade
341          * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
342          * Sec-WebSocket-Origin: http://example.com
343          * Sec-WebSocket-Protocol: chat, superchat
344          * Sec-WebSocket-Version: 4
345          */
346
347          p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", path);
348          p += sprintf(p, "Host: %s\x0d\x0a", host);
349          p += sprintf(p, "Upgrade: websocket\x0d\x0a");
350          p += sprintf(p, "Connection: Upgrade\x0d\x0aSec-WebSocket-Key: ");
351          strcpy(p, key_b64);
352          p += strlen(key_b64);
353          p += sprintf(p, "\x0d\x0aSec-WebSocket-Origin: %s\x0d\x0a", origin);
354          if (protocol != NULL)
355                 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", protocol);
356          p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a\x0d\x0a",
357                                                        wsi->ietf_spec_revision);
358
359
360         /* prepare the expected server accept response */
361
362         strcpy(buf, key_b64);
363         strcpy(&buf[strlen(buf)], magic_websocket_guid);
364
365         SHA1((unsigned char *)buf, strlen(buf), (unsigned char *)hash);
366
367         lws_b64_encode_string(hash, 20, wsi->initial_handshake_hash_base64,
368                                   sizeof wsi->initial_handshake_hash_base64);
369
370         /* send our request to the server */
371
372 #ifdef LWS_OPENSSL_SUPPORT
373         if (ssl_connection)
374                 n = SSL_write(wsi->ssl, pkt, p - pkt);
375         else
376 #endif
377                 n = send(wsi->sock, pkt, p - pkt, 0);
378
379         if (n < 0) {
380                 fprintf(stderr, "ERROR writing to client socket\n");
381                 goto bail2;
382         }
383
384         wsi->parser_state = WSI_TOKEN_NAME_PART;
385
386         pfd.fd = wsi->sock;
387         pfd.events = POLLIN;
388         pfd.revents = 0;
389
390         n = poll(&pfd, 1, 5000);
391         if (n < 0) {
392                 fprintf(stderr, "libwebsocket_client_handshake socket error "
393                                 "while waiting for handshake response");
394                 goto bail2;
395         }
396         if (n == 0) {
397                 fprintf(stderr, "libwebsocket_client_handshake timeout "
398                                 "while waiting for handshake response");
399                 goto bail2;
400         }
401
402         /* interpret the server response */
403
404         /*
405          *  HTTP/1.1 101 Switching Protocols
406          *  Upgrade: websocket
407          *  Connection: Upgrade
408          *  Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
409          *  Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
410          *  Sec-WebSocket-Protocol: chat
411          */
412
413 #ifdef LWS_OPENSSL_SUPPORT
414         if (ssl_connection)
415                 len = SSL_read(wsi->ssl, pkt, sizeof pkt);
416         else
417 #endif
418                 len = recv(wsi->sock, pkt, sizeof pkt, 0);
419
420         if (len < 0) {
421                 fprintf(stderr, "libwebsocket_client_handshake read error\n");
422                 goto bail2;
423         }
424
425         p = pkt;
426         for (n = 0; n < len; n++)
427                 libwebsocket_parse(wsi, *p++);
428
429         if (wsi->parser_state != WSI_PARSING_COMPLETE) {
430                 fprintf(stderr, "libwebsocket_client_handshake server response"
431                                 " failed parsing\n");
432                 goto bail2;
433         }
434
435         /*
436          * well, what the server sent looked reasonable for syntax.
437          * Now let's confirm it sent all the necessary headers
438          */
439
440          if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
441                         !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
442                         !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
443                         !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len ||
444                         !wsi->utf8_token[WSI_TOKEN_NONCE].token_len ||
445                         (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len &&
446                                                             protocol != NULL)) {
447                 fprintf(stderr, "libwebsocket_client_handshake "
448                                                 "missing required header(s)\n");
449                 pkt[len] = '\0';
450                 fprintf(stderr, "%s", pkt);
451                 goto bail2;
452         }
453
454         /*
455          * Everything seems to be there, now take a closer look at what is in
456          * each header
457          */
458
459         strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
460         if (strcmp(wsi->utf8_token[WSI_TOKEN_HTTP].token,
461                                                    "101 switching protocols")) {
462                 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
463                                 " HTTP response '%s'\n",
464                                          wsi->utf8_token[WSI_TOKEN_HTTP].token);
465                 goto bail2;
466         }
467
468         strtolower(wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
469         if (strcmp(wsi->utf8_token[WSI_TOKEN_UPGRADE].token, "websocket")) {
470                 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
471                                 " Upgrade header '%s'\n",
472                                       wsi->utf8_token[WSI_TOKEN_UPGRADE].token);
473                 goto bail2;
474         }
475
476         strtolower(wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
477         if (strcmp(wsi->utf8_token[WSI_TOKEN_CONNECTION].token, "upgrade")) {
478                 fprintf(stderr, "libwebsocket_client_handshake server sent bad"
479                                 " Connection hdr '%s'\n",
480                                    wsi->utf8_token[WSI_TOKEN_CONNECTION].token);
481                 goto bail2;
482         }
483         /*
484          * confirm the protocol the server wants to talk was in the list of
485          * protocols we offered
486          */
487
488         if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
489
490                 /* no protocol name to work from, default to first protocol */
491                 wsi->protocol = &this->protocols[0];
492
493                 goto check_accept;
494         }
495
496         pc = protocol;
497         while (*pc && !okay) {
498                 if ((!strncmp(pc, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
499                         wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len)) &&
500                 (pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == ',' ||
501                    pc[wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len] == '\0')) {
502                         okay = 1;
503                         continue;
504                 }
505                 while (*pc && *pc != ',')
506                         pc++;
507                 while (*pc && *pc != ' ')
508                         pc++;
509         }
510         if (!okay) {
511                 fprintf(stderr, "libwebsocket_client_handshake server "
512                                         "sent bad protocol '%s'\n",
513                              wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
514                 goto bail2;
515         }
516
517         /*
518          * identify the selected protocol struct and set it
519          */
520         n = 0;
521         wsi->protocol = NULL;
522         while (this->protocols[n].callback) {
523                 if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
524                                        this->protocols[n].name) == 0)
525                         wsi->protocol = &this->protocols[n];
526                 n++;
527         }
528
529         if (wsi->protocol == NULL) {
530                 fprintf(stderr, "libwebsocket_client_handshake server "
531                                 "requested protocol '%s', which we "
532                                 "said we supported but we don't!\n",
533                              wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
534                 goto bail2;
535         }
536
537 check_accept:
538         /*
539          * Confirm his accept token is the same as the one we precomputed
540          */
541
542         if (strcmp(wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
543                                           wsi->initial_handshake_hash_base64)) {
544                 fprintf(stderr, "libwebsocket_client_handshake server sent "
545                                 "bad ACCEPT '%s' vs computed '%s'\n",
546                                 wsi->utf8_token[WSI_TOKEN_ACCEPT].token,
547                                             wsi->initial_handshake_hash_base64);
548                 goto bail2;
549         }
550
551         /*
552          * Calculate the masking key to use when sending data to server
553          */
554
555         strcpy(buf, key_b64);
556         p = buf + strlen(key_b64);
557         strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token);
558         p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len;
559         strcpy(p, magic_websocket_04_masking_guid);
560         SHA1((unsigned char *)buf, strlen(buf), wsi->masking_key_04);
561
562         /* allocate the per-connection user memory (if any) */
563
564         if (wsi->protocol->per_session_data_size) {
565                 wsi->user_space = malloc(
566                                   wsi->protocol->per_session_data_size);
567                 if (wsi->user_space  == NULL) {
568                         fprintf(stderr, "Out of memory for "
569                                                    "conn user space\n");
570                         goto bail2;
571                 }
572         } else
573                 wsi->user_space = NULL;
574
575         /* okay he is good to go */
576
577         this->fds[this->fds_count].fd = wsi->sock;
578         this->fds[this->fds_count].revents = 0;
579         this->fds[this->fds_count++].events = POLLIN;
580
581         wsi->state = WSI_STATE_ESTABLISHED;
582         wsi->mode = LWS_CONNMODE_WS_CLIENT;
583
584         fprintf(stderr, "handshake OK for protocol %s\n", wsi->protocol->name);
585
586         /* call him back to inform him he is up */
587
588         wsi->protocol->callback(wsi,
589                          LWS_CALLBACK_CLIENT_ESTABLISHED,
590                          wsi->user_space,
591                          NULL, 0);
592         return wsi;
593
594
595 bail2:
596         libwebsocket_client_close(wsi);
597 bail1:
598         free(wsi);
599
600         return NULL;
601 }