migrate client hs and c_port into ah
[profile/ivi/libwebsockets.git] / lib / client.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-libwebsockets.h"
23
24 #ifdef WIN32
25 #include <tchar.h>
26 #include <io.h>
27 #else
28 #ifdef LWS_BUILTIN_GETIFADDRS
29 #include <getifaddrs.h>
30 #else
31 #include <ifaddrs.h>
32 #endif
33 #include <sys/un.h>
34 #include <sys/socket.h>
35 #include <netdb.h>
36 #endif
37
38 int lws_client_socket_service(struct libwebsocket_context *context,
39                                 struct libwebsocket *wsi, struct pollfd *pollfd)
40 {
41         int n;
42         char *p = (char *)&context->service_buffer[0];
43         int len;
44         char c;
45
46         switch (wsi->mode) {
47
48         case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
49
50                 /* handle proxy hung up on us */
51
52                 if (pollfd->revents & (POLLERR | POLLHUP)) {
53
54                         lwsl_warn("Proxy connection %p (fd=%d) dead\n",
55                                 (void *)wsi, pollfd->fd);
56
57                         libwebsocket_close_and_free_session(context, wsi,
58                                                      LWS_CLOSE_STATUS_NOSTATUS);
59                         return 0;
60                 }
61
62                 n = recv(wsi->sock, context->service_buffer,
63                                         sizeof(context->service_buffer), 0);
64                 if (n < 0) {
65                         libwebsocket_close_and_free_session(context, wsi,
66                                                      LWS_CLOSE_STATUS_NOSTATUS);
67                         lwsl_err("ERROR reading from proxy socket\n");
68                         return 0;
69                 }
70
71                 context->service_buffer[13] = '\0';
72                 if (strcmp((char *)context->service_buffer, "HTTP/1.0 200 ")) {
73                         libwebsocket_close_and_free_session(context, wsi,
74                                                      LWS_CLOSE_STATUS_NOSTATUS);
75                         lwsl_err("ERROR proxy: %s\n", context->service_buffer);
76                         return 0;
77                 }
78
79                 /* clear his proxy connection timeout */
80
81                 libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
82
83                 /* fallthru */
84
85         case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
86
87                 /*
88                  * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
89                  * timeout protection set in client-handshake.c
90                  */
91
92         #ifdef LWS_OPENSSL_SUPPORT
93
94                 /*
95                  * take care of our libwebsocket_callback_on_writable
96                  * happening at a time when there's no real connection yet
97                  */
98
99                 pollfd->events &= ~POLLOUT;
100
101                 /* external POLL support via protocol 0 */
102                 context->protocols[0].callback(context, wsi,
103                         LWS_CALLBACK_CLEAR_MODE_POLL_FD,
104                         (void *)(long)wsi->sock, NULL, POLLOUT);
105
106                 /* we can retry this... just cook the SSL BIO the first time */
107
108                 if (wsi->use_ssl && !wsi->ssl) {
109
110                         wsi->ssl = SSL_new(context->ssl_client_ctx);
111
112 #ifdef USE_CYASSL
113                         /*
114                          * CyaSSL does certificate verification differently
115                          * from OpenSSL.
116                          * If we should ignore the certificate, we need to set
117                          * this before SSL_new and SSL_connect is called.
118                          * Otherwise the connect will simply fail with error
119                          * code -155
120                          */
121                         if (wsi->use_ssl == 2)
122                                 CyaSSL_set_verify(wsi->ssl,
123                                                         SSL_VERIFY_NONE, NULL);
124 #endif /* USE_CYASSL */
125
126                         wsi->client_bio =
127                                 BIO_new_socket(wsi->sock, BIO_NOCLOSE);
128                         SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
129
130 #ifdef USE_CYASSL
131                         CyaSSL_set_using_nonblock(wsi->ssl, 1);
132 #else
133                         BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
134 #endif
135
136                         SSL_set_ex_data(wsi->ssl,
137                                         openssl_websocket_private_data_index,
138                                                                        context);
139                 }
140
141                 if (wsi->use_ssl) {
142                         lws_latency_pre(context, wsi);
143                         n = SSL_connect(wsi->ssl);
144                         lws_latency(context, wsi,
145                           "SSL_connect LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE",
146                                                                       n, n > 0);
147
148                         if (n < 0) {
149                                 n = SSL_get_error(wsi->ssl, n);
150
151                                 if (n == SSL_ERROR_WANT_READ ||
152                                         n == SSL_ERROR_WANT_WRITE) {
153                                         /*
154                                          * wants us to retry connect due to
155                                          * state of the underlying ssl layer...
156                                          * but since it may be stalled on
157                                          * blocked write, no incoming data may
158                                          * arrive to trigger the retry.
159                                          * Force (possibly many times if the SSL
160                                          * state persists in returning the
161                                          * condition code, but other sockets
162                                          * are getting serviced inbetweentimes)
163                                          * us to get called back when writable.
164                                          */
165
166                                         lwsl_info(
167                                              "SSL_connect WANT_... retrying\n");
168                                         libwebsocket_callback_on_writable(
169                                                                   context, wsi);
170
171                                         return 0; /* no error */
172                                 }
173                                 n = -1;
174                         }
175
176                         if (n <= 0) {
177                                 /*
178                                  * retry if new data comes until we
179                                  * run into the connection timeout or win
180                                  */
181
182                                 lwsl_err("SSL connect error %s\n",
183                                         ERR_error_string(ERR_get_error(),
184                                               (char *)context->service_buffer));
185                                 return 0;
186                         }
187
188                         #ifndef USE_CYASSL
189                         /*
190                          * See comment above about CyaSSL certificate
191                          * verification
192                          */
193                         lws_latency_pre(context, wsi);
194                         n = SSL_get_verify_result(wsi->ssl);
195                         lws_latency(context, wsi,
196                                 "SSL_get_verify_result LWS_CONNMODE..HANDSHAKE",
197                                                                       n, n > 0);
198                         if ((n != X509_V_OK) && (
199                                 n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
200                                                            wsi->use_ssl != 2)) {
201
202                                 lwsl_err(
203                                       "server's cert didn't look good %d\n", n);
204                                 libwebsocket_close_and_free_session(context,
205                                                 wsi, LWS_CLOSE_STATUS_NOSTATUS);
206                                 return 0;
207                         }
208 #endif /* USE_CYASSL */
209                 } else
210                         wsi->ssl = NULL;
211 #endif
212
213                 p = libwebsockets_generate_client_handshake(context, wsi, p);
214                 if (p == NULL) {
215                         lwsl_err("Failed to generate handshake for client\n");
216                         libwebsocket_close_and_free_session(context, wsi,
217                                                      LWS_CLOSE_STATUS_NOSTATUS);
218                         return 0;
219                 }
220
221                 /* send our request to the server */
222
223                 lws_latency_pre(context, wsi);
224 #ifdef LWS_OPENSSL_SUPPORT
225                 if (wsi->use_ssl)
226                         n = SSL_write(wsi->ssl, context->service_buffer,
227                                            p - (char *)context->service_buffer);
228                 else
229 #endif
230                         n = send(wsi->sock, context->service_buffer,
231                                         p - (char *)context->service_buffer, 0);
232                 lws_latency(context, wsi,
233                         "send or SSL_write LWS_CONNMODE...HANDSHAKE",
234                                                                      n, n >= 0);
235
236                 if (n < 0) {
237                         lwsl_debug("ERROR writing to client socket\n");
238                         libwebsocket_close_and_free_session(context, wsi,
239                                                      LWS_CLOSE_STATUS_NOSTATUS);
240                         return 0;
241                 }
242
243                 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
244                 wsi->u.hdr.lextable_pos = 0;
245                 wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY;
246                 libwebsocket_set_timeout(wsi,
247                                 PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
248                                                               AWAITING_TIMEOUT);
249                 break;
250
251         case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
252
253                 /* handle server hung up on us */
254
255                 if (pollfd->revents & (POLLERR | POLLHUP)) {
256
257                         lwsl_debug("Server connection %p (fd=%d) dead\n",
258                                 (void *)wsi, pollfd->fd);
259
260                         goto bail3;
261                 }
262
263                 if (!(pollfd->revents & POLLIN)) {
264                         lwsl_warn("server reply no POLLIN\n");
265                         goto bail3;
266                 }
267
268                 /* interpret the server response */
269
270                 /*
271                  *  HTTP/1.1 101 Switching Protocols
272                  *  Upgrade: websocket
273                  *  Connection: Upgrade
274                  *  Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
275                  *  Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
276                  *  Sec-WebSocket-Protocol: chat
277                  */
278
279                 /*
280                  * we have to take some care here to only take from the
281                  * socket bytewise.  The browser may (and has been seen to
282                  * in the case that onopen() performs websocket traffic)
283                  * coalesce both handshake response and websocket traffic
284                  * in one packet, since at that point the connection is
285                  * definitively ready from browser pov.
286                  */
287
288                 len = 1;
289                 while (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE &&
290                                                                       len > 0) {
291 #ifdef LWS_OPENSSL_SUPPORT
292                         if (wsi->use_ssl) {
293                                 len = SSL_read(wsi->ssl, &c, 1);
294                                 if (len < 0) {
295                                         n = SSL_get_error(wsi->ssl, len);
296                                         if (n ==  SSL_ERROR_WANT_READ ||
297                                                      n ==  SSL_ERROR_WANT_WRITE)
298                                                 return 0;
299                                 }
300                         } else
301 #endif
302                                 len = recv(wsi->sock, &c, 1, 0);
303
304                         if (len < 0) {
305                                 lwsl_warn("error on parsing recv\n");
306                                 goto bail3;
307                         }
308
309                         if (libwebsocket_parse(wsi, c)) {
310                                 lwsl_warn("problems parsing header\n");
311                                 goto bail3;
312                         }
313                 }
314
315                 /*
316                  * hs may also be coming in multiple packets, there is a 5-sec
317                  * libwebsocket timeout still active here too, so if parsing did
318                  * not complete just wait for next packet coming in this state
319                  */
320
321                 if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
322                         break;
323
324                 /*
325                  * otherwise deal with the handshake.  If there's any
326                  * packet traffic already arrived we'll trigger poll() again
327                  * right away and deal with it that way
328                  */
329
330                 return lws_client_interpret_server_handshake(context, wsi);
331
332 bail3:
333                 lwsl_info(
334                         "closing connection at LWS_CONNMODE...SERVER_REPLY\n");
335                 libwebsocket_close_and_free_session(context, wsi,
336                                                     LWS_CLOSE_STATUS_NOSTATUS);
337                 return 0;
338
339         case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
340                 lwsl_ext("LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT\n");
341                 break;
342
343         case LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD:
344                 lwsl_ext("LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD\n");
345                 break;
346         default:
347                 break;
348         }
349
350         return 0;
351 }
352
353
354 /*
355  * In-place str to lower case
356  */
357
358 static void
359 strtolower(char *s)
360 {
361         while (*s) {
362                 *s = tolower(*s);
363                 s++;
364         }
365 }
366
367 int
368 lws_client_interpret_server_handshake(struct libwebsocket_context *context,
369                 struct libwebsocket *wsi)
370 {
371         const char *pc;
372         int okay = 0;
373         char *p;
374         int len;
375 #ifndef LWS_NO_EXTENSIONS
376         char ext_name[128];
377         struct libwebsocket_extension *ext;
378         void *v;
379         int more = 1;
380         const char *c;
381 #endif
382         int n;
383
384         /*
385          * well, what the server sent looked reasonable for syntax.
386          * Now let's confirm it sent all the necessary headers
387          */
388
389         if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
390                 lwsl_info("no ACCEPT\n");
391                 goto bail3;
392         }
393
394         p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
395         if (!p) {
396                 lwsl_info("no URI\n");
397                 goto bail3;
398         }
399         if (p && strncmp(p, "101", 3)) {
400                 lwsl_warn(
401                        "lws_client_handshake: got bad HTTP response '%s'\n", p);
402                 goto bail3;
403         }
404
405         p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);
406         if (!p) {
407                 lwsl_info("no UPGRADE\n");
408                 goto bail3;
409         }
410         strtolower(p);
411         if (strcmp(p, "websocket")) {
412                 lwsl_warn(
413                       "lws_client_handshake: got bad Upgrade header '%s'\n", p);
414                 goto bail3;
415         }
416
417         p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION);
418         if (!p) {
419                 lwsl_info("no Connection hdr\n");
420                 goto bail3;
421         }
422         strtolower(p);
423         if (strcmp(p, "upgrade")) {
424                 lwsl_warn("lws_client_int_s_hs: bad header %s\n", p);
425                 goto bail3;
426         }
427
428         pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
429         if (pc == NULL)
430                 lwsl_parser("lws_client_int_s_hs: no protocol list\n");
431         else
432                 lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc);
433
434         /*
435          * confirm the protocol the server wants to talk was in the list
436          * of protocols we offered
437          */
438
439         len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
440         if (!len) {
441
442                 lwsl_info("lws_client_int_s_hs: WSI_TOKEN_PROTOCOL is null\n");
443                 /*
444                  * no protocol name to work from,
445                  * default to first protocol
446                  */
447                 wsi->protocol = &context->protocols[0];
448                 goto check_extensions;
449         }
450
451         p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
452         len = strlen(p);
453
454         while (*pc && !okay) {
455                 if (!strncmp(pc, p, len) &&
456                                           (pc[len] == ',' || pc[len] == '\0')) {
457                         okay = 1;
458                         continue;
459                 }
460                 while (*pc && *pc != ',')
461                         pc++;
462                 while (*pc && *pc != ' ')
463                         pc++;
464         }
465
466         if (!okay) {
467                 lwsl_err("lws_client_int_s_hs: got bad protocol %s\n", p);
468                 goto bail2;
469         }
470
471         /*
472          * identify the selected protocol struct and set it
473          */
474         n = 0;
475         wsi->protocol = NULL;
476         while (context->protocols[n].callback && !wsi->protocol) {
477                 if (strcmp(p, context->protocols[n].name) == 0) {
478                         wsi->protocol = &context->protocols[n];
479                         break;
480                 }
481                 n++;
482         }
483
484         if (wsi->protocol == NULL) {
485                 lwsl_err("lws_client_int_s_hs: fail protocol %s\n", p);
486                 goto bail2;
487         }
488
489
490 check_extensions:
491 #ifndef LWS_NO_EXTENSIONS
492         /* instantiate the accepted extensions */
493
494         if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
495                 lwsl_ext("no client extenstions allowed by server\n");
496                 goto check_accept;
497         }
498
499         /*
500          * break down the list of server accepted extensions
501          * and go through matching them or identifying bogons
502          */
503
504         if (lws_hdr_copy(wsi, (char *)context->service_buffer,
505                    sizeof(context->service_buffer), WSI_TOKEN_EXTENSIONS) < 0) {
506                 lwsl_warn("ext list from server failed to copy\n");
507                 goto bail2;
508         }
509
510         c = (char *)context->service_buffer;
511         n = 0;
512         while (more) {
513
514                 if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
515                         ext_name[n] = *c++;
516                         if (n < sizeof(ext_name) - 1)
517                                 n++;
518                         continue;
519                 }
520                 ext_name[n] = '\0';
521                 if (!*c)
522                         more = 0;
523                 else {
524                         c++;
525                         if (!n)
526                                 continue;
527                 }
528
529                 /* check we actually support it */
530
531                 lwsl_ext("checking client ext %s\n", ext_name);
532
533                 n = 0;
534                 ext = wsi->protocol->owning_server->extensions;
535                 while (ext && ext->callback) {
536
537                         if (strcmp(ext_name, ext->name)) {
538                                 ext++;
539                                 continue;
540                         }
541
542                         n = 1;
543
544                         lwsl_ext("instantiating client ext %s\n", ext_name);
545
546                         /* instantiate the extension on this conn */
547
548                         wsi->active_extensions_user[
549                                 wsi->count_active_extensions] =
550                                          malloc(ext->per_session_data_size);
551                         if (wsi->active_extensions_user[
552                                 wsi->count_active_extensions] == NULL) {
553                                 lwsl_err("Out of mem\n");
554                                 goto bail2;
555                         }
556                         memset(wsi->active_extensions_user[
557                                 wsi->count_active_extensions], 0,
558                                                     ext->per_session_data_size);
559                         wsi->active_extensions[
560                                   wsi->count_active_extensions] = ext;
561
562                         /* allow him to construct his context */
563
564                         ext->callback(wsi->protocol->owning_server,
565                                 ext, wsi,
566                                    LWS_EXT_CALLBACK_CLIENT_CONSTRUCT,
567                                         wsi->active_extensions_user[
568                                          wsi->count_active_extensions],
569                                                                    NULL, 0);
570
571                         wsi->count_active_extensions++;
572
573                         ext++;
574                 }
575
576                 if (n == 0) {
577                         lwsl_warn("Unknown ext '%s'!\n", ext_name);
578                         goto bail2;
579                 }
580
581                 n = 0;
582         }
583
584 check_accept:
585 #endif
586
587         /*
588          * Confirm his accept token is the one we precomputed
589          */
590
591         p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);
592         if (strcmp(p, wsi->u.hdr.ah->initial_handshake_hash_base64)) {
593                 lwsl_warn("lws_client_int_s_hs: accept %s wrong vs %s\n", p,
594                                   wsi->u.hdr.ah->initial_handshake_hash_base64);
595                 goto bail2;
596         }
597
598         /* allocate the per-connection user memory (if any) */
599         if (wsi->protocol->per_session_data_size &&
600                                          !libwebsocket_ensure_user_space(wsi)) {
601                 lwsl_err("Problem allocating wsi user mem\n");
602                 goto bail2;
603         }
604
605         /*
606          * we seem to be good to go, give client last chance to check
607          * headers and OK it
608          */
609
610         wsi->protocol->callback(context, wsi,
611                                 LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
612                                                      wsi->user_space, NULL, 0);
613
614         /* clear his proxy connection timeout */
615
616         libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
617
618         /* free up his parsing allocations */
619         if (wsi->u.hdr.ah)
620                 free(wsi->u.hdr.ah);
621
622         /* mark him as being alive */
623
624         wsi->state = WSI_STATE_ESTABLISHED;
625         wsi->mode = LWS_CONNMODE_WS_CLIENT;
626
627         /* union transition */
628
629         memset(&wsi->u, 0, sizeof(wsi->u));
630
631         /*
632          * create the frame buffer for this connection according to the
633          * size mentioned in the protocol definition.  If 0 there, then
634          * use a big default for compatibility
635          */
636
637         n = wsi->protocol->rx_buffer_size;
638         if (!n)
639                 n = LWS_MAX_SOCKET_IO_BUF;
640         n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
641         wsi->u.ws.rx_user_buffer = malloc(n);
642         if (!wsi->u.ws.rx_user_buffer) {
643                 lwsl_err("Out of Mem allocating rx buffer %d\n", n);
644                 goto bail3;
645         }
646         lwsl_info("Allocating client RX buffer %d\n", n);
647
648         lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
649
650         /* call him back to inform him he is up */
651
652         wsi->protocol->callback(context, wsi,
653                                 LWS_CALLBACK_CLIENT_ESTABLISHED,
654                                                      wsi->user_space, NULL, 0);
655 #ifndef LWS_NO_EXTENSIONS
656         /*
657          * inform all extensions, not just active ones since they
658          * already know
659          */
660
661         ext = context->extensions;
662
663         while (ext && ext->callback) {
664                 v = NULL;
665                 for (n = 0; n < wsi->count_active_extensions; n++)
666                         if (wsi->active_extensions[n] == ext)
667                                 v = wsi->active_extensions_user[n];
668
669                 ext->callback(context, ext, wsi,
670                           LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, v, NULL, 0);
671                 ext++;
672         }
673 #endif
674
675         return 0;
676
677 bail3:
678
679 bail2:
680         if (wsi->protocol)
681                 wsi->protocol->callback(context, wsi,
682                         LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
683                                                       wsi->user_space, NULL, 0);
684
685         lwsl_info("closing connection due to bail2 connection error\n");
686
687         /* free up his parsing allocations */
688
689         if (wsi->u.hdr.ah)
690                 free(wsi->u.hdr.ah);
691
692         libwebsocket_close_and_free_session(context, wsi,
693                                                  LWS_CLOSE_STATUS_PROTOCOL_ERR);
694
695         return 1;
696 }
697
698
699 char *
700 libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
701                 struct libwebsocket *wsi, char *pkt)
702 {
703         char buf[128];
704         char hash[20];
705         char key_b64[40];
706         char *p = pkt;
707         int n;
708 #ifndef LWS_NO_EXTENSIONS
709         struct libwebsocket_extension *ext;
710         struct libwebsocket_extension *ext1;
711         int ext_count = 0;
712 #endif
713
714         /*
715          * create the random key
716          */
717
718         n = libwebsockets_get_random(context, hash, 16);
719         if (n != 16) {
720                 lwsl_err("Unable to read from random dev %s\n",
721                                                 SYSTEM_RANDOM_FILEPATH);
722                 libwebsocket_close_and_free_session(context, wsi,
723                                              LWS_CLOSE_STATUS_NOSTATUS);
724                 return NULL;
725         }
726
727         lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));
728
729         /*
730          * 00 example client handshake
731          *
732          * GET /socket.io/websocket HTTP/1.1
733          * Upgrade: WebSocket
734          * Connection: Upgrade
735          * Host: 127.0.0.1:9999
736          * Origin: http://127.0.0.1
737          * Sec-WebSocket-Key1: 1 0 2#0W 9 89 7  92 ^
738          * Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
739          * Cookie: socketio=websocket
740          *
741          * (Á®Ä0¶†≥
742          *
743          * 04 example client handshake
744          *
745          * GET /chat HTTP/1.1
746          * Host: server.example.com
747          * Upgrade: websocket
748          * Connection: Upgrade
749          * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
750          * Sec-WebSocket-Origin: http://example.com
751          * Sec-WebSocket-Protocol: chat, superchat
752          * Sec-WebSocket-Version: 4
753          */
754
755         p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a",
756                                 lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
757
758         p += sprintf(p,
759                 "Pragma: no-cache\x0d\x0a""Cache-Control: no-cache\x0d\x0a");
760
761         p += sprintf(p, "Host: %s\x0d\x0a",
762                                lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
763         p += sprintf(p,
764 "Upgrade: websocket\x0d\x0a""Connection: Upgrade\x0d\x0a""Sec-WebSocket-Key: ");
765         strcpy(p, key_b64);
766         p += strlen(key_b64);
767         p += sprintf(p, "\x0d\x0a");
768         if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN))
769                 p += sprintf(p, "Origin: %s\x0d\x0a",
770                              lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));
771
772         if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
773                 p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
774                      lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));
775
776         /* tell the server what extensions we could support */
777
778         p += sprintf(p, "Sec-WebSocket-Extensions: ");
779 #ifndef LWS_NO_EXTENSIONS
780         ext = context->extensions;
781         while (ext && ext->callback) {
782
783                 n = 0;
784                 ext1 = context->extensions;
785
786                 while (ext1 && ext1->callback) {
787                         n |= ext1->callback(context, ext1, wsi,
788                                 LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
789                                         NULL, (char *)ext->name, 0);
790
791                         ext1++;
792                 }
793
794                 if (n) { /* an extension vetos us */
795                         lwsl_ext("ext %s vetoed\n", (char *)ext->name);
796                         ext++;
797                         continue;
798                 }
799
800                 n = context->protocols[0].callback(context, wsi,
801                         LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
802                                 wsi->user_space, (char *)ext->name, 0);
803
804                 /*
805                  * zero return from callback means
806                  * go ahead and allow the extension,
807                  * it's what we get if the callback is
808                  * unhandled
809                  */
810
811                 if (n) {
812                         ext++;
813                         continue;
814                 }
815
816                 /* apply it */
817
818                 if (ext_count)
819                         *p++ = ',';
820                 p += sprintf(p, "%s", ext->name);
821                 ext_count++;
822
823                 ext++;
824         }
825 #endif
826         p += sprintf(p, "\x0d\x0a");
827
828         if (wsi->ietf_spec_revision)
829                 p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
830                                                wsi->ietf_spec_revision);
831
832         /* give userland a chance to append, eg, cookies */
833
834         context->protocols[0].callback(context, wsi,
835                 LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
836                 NULL, &p, (pkt + sizeof(context->service_buffer)) - p - 12);
837
838         p += sprintf(p, "\x0d\x0a");
839
840         /* prepare the expected server accept response */
841
842         key_b64[39] = '\0'; /* enforce composed length below buf sizeof */
843         n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64);
844
845         SHA1((unsigned char *)buf, n, (unsigned char *)hash);
846
847         lws_b64_encode_string(hash, 20,
848                         wsi->u.hdr.ah->initial_handshake_hash_base64,
849                           sizeof(wsi->u.hdr.ah->initial_handshake_hash_base64));
850
851         return p;
852 }
853