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