fix heap corruption if HTTP callback calls libwebsocket_close_and_free_session
[platform/upstream/libwebsockets.git] / lib / handshake.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 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
25 static int
26 interpret_key(const char *key, unsigned long *result)
27 {
28         char digits[20];
29         int digit_pos = 0;
30         const char *p = key;
31         unsigned int spaces = 0;
32         unsigned long acc = 0;
33         int rem = 0;
34
35         while (*p) {
36                 if (isdigit(*p)) {
37                         if (digit_pos == sizeof(digits) - 1)
38                                 return -1;
39                         digits[digit_pos++] = *p;
40                 }
41                 p++;
42         }
43         digits[digit_pos] = '\0';
44         if (!digit_pos)
45                 return -2;
46
47         while (*key) {
48                 if (*key == ' ')
49                         spaces++;
50                 key++;
51         }
52
53         if (!spaces)
54                 return -3;
55
56         p = &digits[0];
57         while (*p) {
58                 rem = (rem * 10) + ((*p++) - '0');
59                 acc = (acc * 10) + (rem / spaces);
60                 rem -= (rem / spaces) * spaces;
61         }
62
63         if (rem) {
64                 fprintf(stderr, "nonzero handshake remainder\n");
65                 return -1;
66         }
67
68         *result = acc;
69
70         return 0;
71 }
72
73
74 static int
75 handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi)
76 {
77         unsigned long key1, key2;
78         unsigned char sum[16];
79         char *response;
80         char *p;
81         int n;
82
83         /* Confirm we have all the necessary pieces */
84
85         if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
86                 !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
87                 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
88                 !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
89                              !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
90                 /* completed header processing, but missing some bits */
91                 goto bail;
92
93         /* allocate the per-connection user memory (if any) */
94         if (wsi->protocol->per_session_data_size && !libwebsocket_ensure_user_space(wsi))
95           goto bail;
96
97         /* create the response packet */
98
99         /* make a buffer big enough for everything */
100
101         response = malloc(256 +
102                 wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
103                 wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
104                 wsi->utf8_token[WSI_TOKEN_HOST].token_len +
105                 wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
106                 wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
107                 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
108         if (!response) {
109                 fprintf(stderr, "Out of memory for response buffer\n");
110                 goto bail;
111         }
112
113         p = response;
114         strcpy(p,   "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
115                                           "Upgrade: WebSocket\x0d\x0a");
116         p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
117                                           "Upgrade: WebSocket\x0d\x0a");
118         strcpy(p,   "Connection: Upgrade\x0d\x0a"
119                     "Sec-WebSocket-Origin: ");
120         p += strlen("Connection: Upgrade\x0d\x0a"
121                     "Sec-WebSocket-Origin: ");
122         strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
123         p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
124 #ifdef LWS_OPENSSL_SUPPORT
125         if (wsi->ssl) {
126                 strcpy(p,   "\x0d\x0aSec-WebSocket-Location: wss://");
127                 p += strlen("\x0d\x0aSec-WebSocket-Location: wss://");
128         } else {
129 #endif
130                 strcpy(p,   "\x0d\x0aSec-WebSocket-Location: ws://");
131                 p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
132 #ifdef LWS_OPENSSL_SUPPORT
133         }
134 #endif
135         strcpy(p, wsi->utf8_token[WSI_TOKEN_HOST].token);
136         p += wsi->utf8_token[WSI_TOKEN_HOST].token_len;
137         strcpy(p, wsi->utf8_token[WSI_TOKEN_GET_URI].token);
138         p += wsi->utf8_token[WSI_TOKEN_GET_URI].token_len;
139
140         if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
141                 strcpy(p,   "\x0d\x0aSec-WebSocket-Protocol: ");
142                 p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
143                 strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
144                 p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
145         }
146
147         strcpy(p,   "\x0d\x0a\x0d\x0a");
148         p += strlen("\x0d\x0a\x0d\x0a");
149
150         /* convert the two keys into 32-bit integers */
151
152         if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
153                 goto bail;
154         if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
155                 goto bail;
156
157         /* lay them out in network byte order (MSB first */
158
159         sum[0] = key1 >> 24;
160         sum[1] = key1 >> 16;
161         sum[2] = key1 >> 8;
162         sum[3] = key1;
163         sum[4] = key2 >> 24;
164         sum[5] = key2 >> 16;
165         sum[6] = key2 >> 8;
166         sum[7] = key2;
167
168         /* follow them with the challenge token we were sent */
169
170         memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
171
172         /*
173          * compute the md5sum of that 16-byte series and use as our
174          * payload after our headers
175          */
176
177         MD5(sum, 16, (unsigned char *)p);
178         p += 16;
179
180         /* it's complete: go ahead and send it */
181
182         debug("issuing response packet %d len\n", (int)(p - response));
183 #ifdef DEBUG
184         fwrite(response, 1,  p - response, stderr);
185 #endif
186         n = libwebsocket_write(wsi, (unsigned char *)response,
187                                           p - response, LWS_WRITE_HTTP);
188         if (n < 0) {
189                 fprintf(stderr, "ERROR writing to socket");
190                 goto bail;
191         }
192
193         /* alright clean up and set ourselves into established state */
194
195         free(response);
196         wsi->state = WSI_STATE_ESTABLISHED;
197         wsi->lws_rx_parse_state = LWS_RXPS_NEW;
198
199         /* notify user code that we're ready to roll */
200
201         if (wsi->protocol->callback)
202                 wsi->protocol->callback(wsi->protocol->owning_server,
203                                 wsi, LWS_CALLBACK_ESTABLISHED,
204                                           wsi->user_space, NULL, 0);
205
206         return 0;
207
208 bail:
209         return -1;
210 }
211
212 /*
213  * Perform the newer BASE64-encoded handshake scheme
214  */
215
216 static int
217 handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi)
218 {
219         static const char *websocket_magic_guid_04 =
220                                          "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
221         static const char *websocket_magic_guid_04_masking =
222                                          "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
223         char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37];
224         char nonce_buf[256];
225         char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37];
226         unsigned char hash[20];
227         int n;
228         char *response;
229         char *p;
230         char *m = mask_summing_buf;
231         int nonce_len = 0;
232         int accept_len;
233         char *c;
234         char ext_name[128];
235         struct libwebsocket_extension * ext;
236         int ext_count = 0;
237         int more = 1;
238
239         if (!wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
240             !wsi->utf8_token[WSI_TOKEN_KEY].token_len) {
241                 debug("handshake_04 missing pieces\n");
242                 /* completed header processing, but missing some bits */
243                 goto bail;
244         }
245
246         if (wsi->utf8_token[WSI_TOKEN_KEY].token_len >=
247                                                      MAX_WEBSOCKET_04_KEY_LEN) {
248                 fprintf(stderr, "Client sent handshake key longer "
249                            "than max supported %d\n", MAX_WEBSOCKET_04_KEY_LEN);
250                 goto bail;
251         }
252
253         strcpy(accept_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
254         strcpy(accept_buf + wsi->utf8_token[WSI_TOKEN_KEY].token_len,
255                                                        websocket_magic_guid_04);
256
257         SHA1((unsigned char *)accept_buf,
258                         wsi->utf8_token[WSI_TOKEN_KEY].token_len +
259                                          strlen(websocket_magic_guid_04), hash);
260
261         accept_len = lws_b64_encode_string((char *)hash, 20, accept_buf,
262                                                              sizeof accept_buf);
263         if (accept_len < 0) {
264                 fprintf(stderr, "Base64 encoded hash too long\n");
265                 goto bail;
266         }
267
268         /* allocate the per-connection user memory (if any) */
269         if (wsi->protocol->per_session_data_size && !libwebsocket_ensure_user_space(wsi))
270           goto bail;
271
272         /* create the response packet */
273
274         /* make a buffer big enough for everything */
275
276         response = malloc(256 +
277                 wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
278                 wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
279                 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
280         if (!response) {
281                 fprintf(stderr, "Out of memory for response buffer\n");
282                 goto bail;
283         }
284
285         p = response;
286         strcpy(p,   "HTTP/1.1 101 Switching Protocols\x0d\x0a"
287                                           "Upgrade: WebSocket\x0d\x0a");
288         p += strlen("HTTP/1.1 101 Switching Protocols\x0d\x0a"
289                                           "Upgrade: WebSocket\x0d\x0a");
290         strcpy(p,   "Connection: Upgrade\x0d\x0a"
291                     "Sec-WebSocket-Accept: ");
292         p += strlen("Connection: Upgrade\x0d\x0a"
293                     "Sec-WebSocket-Accept: ");
294         strcpy(p, accept_buf);
295         p += accept_len;
296
297         if (wsi->ietf_spec_revision == 4) {
298                 strcpy(p,   "\x0d\x0aSec-WebSocket-Nonce: ");
299                 p += strlen("\x0d\x0aSec-WebSocket-Nonce: ");
300
301                 /* select the nonce */
302
303                 n = libwebsockets_get_random(wsi->protocol->owning_server,
304                                                                       hash, 16);
305                 if (n != 16) {
306                         fprintf(stderr, "Unable to read random device %s %d\n",
307                                                      SYSTEM_RANDOM_FILEPATH, n);
308                         if (wsi->user_space)
309                                 free(wsi->user_space);
310                         goto bail;
311                 }
312
313                 /* encode the nonce */
314
315                 nonce_len = lws_b64_encode_string((const char *)hash, 16,
316                                                    nonce_buf, sizeof nonce_buf);
317                 if (nonce_len < 0) {
318                         fprintf(stderr, "Failed to base 64 encode the nonce\n");
319                         if (wsi->user_space)
320                                 free(wsi->user_space);
321                         goto bail;
322                 }
323
324                 /* apply the nonce */
325
326                 strcpy(p, nonce_buf);
327                 p += nonce_len;
328         }
329
330         if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
331                 strcpy(p,   "\x0d\x0aSec-WebSocket-Protocol: ");
332                 p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
333                 strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
334                 p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
335         }
336
337         /*
338          * Figure out which extensions the client has that we want to
339          * enable on this connection, and give him back the list
340          */
341
342         if (wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token_len) {
343
344                 /*
345                  * break down the list of client extensions
346                  * and go through them
347                  */
348
349                 c = wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token;
350                 debug("wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token = %s\n", wsi->utf8_token[WSI_TOKEN_EXTENSIONS].token);
351                 wsi->count_active_extensions = 0;
352                 n = 0;
353                 while (more) {
354                 
355                         if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
356                                 ext_name[n] = *c++;
357                                 if (n < sizeof(ext_name) - 1)
358                                         n++;
359                                 continue;
360                         }
361                         ext_name[n] = '\0';
362                         if (!*c)
363                                 more = 0;
364                         else {
365                                 c++;
366                                 if (!n)
367                                         continue;
368                         }
369
370                         /* check a client's extension against our support */
371
372                         ext = wsi->protocol->owning_server->extensions;
373
374                         while (ext && ext->callback) {
375
376                                 if (strcmp(ext_name, ext->name)) {
377                                         ext++;
378                                         continue;
379                                 }
380
381                                 /*
382                                  * oh, we do support this one he
383                                  * asked for... but let's ask user
384                                  * code if it's OK to apply it on this
385                                  * particular connection + protocol
386                                  */
387
388                                 n = wsi->protocol->owning_server->
389                                         protocols[0].callback(
390                                                 wsi->protocol->owning_server,
391                                                 wsi,
392                                           LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
393                                                   wsi->user_space, ext_name, 0);
394
395                                 /*
396                                  * zero return from callback means
397                                  * go ahead and allow the extension,
398                                  * it's what we get if the callback is
399                                  * unhandled
400                                  */
401
402                                 if (n) {
403                                         ext++;
404                                         continue;
405                                 }
406
407                                 /* apply it */
408                                 
409                                 if (ext_count)
410                                         *p++ = ',';
411                                 else {
412                                         strcpy(p,   "\x0d\x0aSec-WebSocket-Extensions: ");
413                                         p += strlen("\x0d\x0aSec-WebSocket-Extensions: ");
414                                 }
415                                 p += sprintf(p, "%s", ext_name);
416                                 ext_count++;
417
418                                 /* instantiate the extension on this conn */
419
420                                 wsi->active_extensions_user[
421                                         wsi->count_active_extensions] =
422                                              malloc(ext->per_session_data_size);
423                                 memset(wsi->active_extensions_user[
424                                         wsi->count_active_extensions], 0,
425                                                     ext->per_session_data_size);
426                                                         
427                                 wsi->active_extensions[
428                                           wsi->count_active_extensions] = ext;
429
430                                 /* allow him to construct his context */
431
432                                 ext->callback(wsi->protocol->owning_server,
433                                                 ext, wsi,
434                                                 LWS_EXT_CALLBACK_CONSTRUCT,
435                                                 wsi->active_extensions_user[
436                                         wsi->count_active_extensions], NULL, 0);
437
438                                 wsi->count_active_extensions++;
439                                 debug("wsi->count_active_extensions <- %d",
440                                                   wsi->count_active_extensions);
441
442                                 ext++;
443                         }
444
445                         n = 0;
446                 }
447         }
448
449         /* end of response packet */
450
451         strcpy(p,   "\x0d\x0a\x0d\x0a");
452         p += strlen("\x0d\x0a\x0d\x0a");
453
454         if (wsi->ietf_spec_revision == 4) {
455
456                 /*
457                  * precompute the masking key the client will use from the SHA1
458                  * hash of ( base 64 client key we were sent, concatenated with
459                  * the bse 64 nonce we sent, concatenated with a magic constant
460                  * guid specified by the 04 standard )
461                  *
462                  * We store the hash in the connection's wsi ready to use with
463                  * undoing the masking the client has done on framed data it
464                  * sends (we send our data to the client in clear).
465                  */
466
467                 strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
468                 m += wsi->utf8_token[WSI_TOKEN_KEY].token_len;
469                 strcpy(m, nonce_buf);
470                 m += nonce_len;
471                 strcpy(m, websocket_magic_guid_04_masking);
472                 m += strlen(websocket_magic_guid_04_masking);
473
474                 SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf,
475                                                            wsi->masking_key_04);
476         }
477
478         if (!lws_any_extension_handled(context, wsi,
479                         LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
480                                                                 response, p - response)) {
481
482                 /* okay send the handshake response accepting the connection */
483
484                 debug("issuing response packet %d len\n", (int)(p - response));
485         #ifdef DEBUG
486                 fwrite(response, 1,  p - response, stderr);
487         #endif
488                 n = libwebsocket_write(wsi, (unsigned char *)response,
489                                                   p - response, LWS_WRITE_HTTP);
490                 if (n < 0) {
491                         fprintf(stderr, "ERROR writing to socket");
492                         goto bail;
493                 }
494
495         }
496
497         /* alright clean up and set ourselves into established state */
498
499         free(response);
500         wsi->state = WSI_STATE_ESTABLISHED;
501         wsi->lws_rx_parse_state = LWS_RXPS_NEW;
502         wsi->rx_packet_length = 0;
503
504         /* notify user code that we're ready to roll */
505
506         if (wsi->protocol->callback)
507                 wsi->protocol->callback(wsi->protocol->owning_server,
508                                 wsi, LWS_CALLBACK_ESTABLISHED,
509                                           wsi->user_space, NULL, 0);
510
511         return 0;
512
513
514 bail:
515         return -1;
516 }
517
518
519 /*
520  * -04 of the protocol (actually the 80th version) has a radically different
521  * handshake.  The 04 spec gives the following idea
522  *
523  *    The handshake from the client looks as follows:
524  *
525  *      GET /chat HTTP/1.1
526  *      Host: server.example.com
527  *      Upgrade: websocket
528  *      Connection: Upgrade
529  *      Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
530  *      Sec-WebSocket-Origin: http://example.com
531  *      Sec-WebSocket-Protocol: chat, superchat
532  *      Sec-WebSocket-Version: 4
533  *
534  *  The handshake from the server looks as follows:
535  *
536  *       HTTP/1.1 101 Switching Protocols
537  *       Upgrade: websocket
538  *       Connection: Upgrade
539  *       Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
540  *       Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
541  *       Sec-WebSocket-Protocol: chat
542  */
543
544 /*
545  * We have to take care about parsing because the headers may be split
546  * into multiple fragments.  They may contain unknown headers with arbitrary
547  * argument lengths.  So, we parse using a single-character at a time state
548  * machine that is completely independent of packet size.
549  */
550
551 int
552 libwebsocket_read(struct libwebsocket_context *context, struct libwebsocket *wsi,
553                                                 unsigned char * buf, size_t len)
554 {
555         size_t n;
556
557         switch (wsi->state) {
558         case WSI_STATE_HTTP:
559                 wsi->state = WSI_STATE_HTTP_HEADERS;
560                 wsi->parser_state = WSI_TOKEN_NAME_PART;
561                 /* fallthru */
562         case WSI_STATE_HTTP_HEADERS:
563
564                 debug("issuing %d bytes to parser\n", (int)len);
565 #ifdef DEBUG
566                 fwrite(buf, 1, len, stderr);
567 #endif
568
569                 switch (wsi->mode) {
570                 case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
571                 case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
572                 case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
573                 case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
574                 case LWS_CONNMODE_WS_CLIENT:
575                         for (n = 0; n < len; n++)
576                                 libwebsocket_client_rx_sm(wsi, *buf++);
577
578                         return 0;
579                 default:
580                         break;
581                 }
582                 
583                 /* LWS_CONNMODE_WS_SERVING */
584
585                 for (n = 0; n < len; n++)
586                         libwebsocket_parse(wsi, *buf++);
587
588                 if (wsi->parser_state != WSI_PARSING_COMPLETE)
589                         break;
590
591                 debug("seem to be serving, mode is %d\n", wsi->mode);
592
593                 debug("libwebsocket_parse sees parsing complete\n");
594
595                 /* is this websocket protocol or normal http 1.0? */
596
597                 if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
598                              !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len) {
599                         wsi->state = WSI_STATE_HTTP;
600                         if (wsi->protocol->callback)
601                                 (wsi->protocol->callback)(context, wsi,
602                                    LWS_CALLBACK_HTTP, wsi->user_space,
603                                    wsi->utf8_token[WSI_TOKEN_GET_URI].token, 0);
604                         return 0;
605                 }
606
607                 if (!wsi->protocol)
608                         fprintf(stderr, "NULL protocol coming on libwebsocket_read\n");
609
610                 /*
611                  * It's websocket
612                  *
613                  * Make sure user side is happy about protocol
614                  */
615
616                 while (wsi->protocol->callback) {
617
618                         if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL) {
619                                 if (wsi->protocol->name == NULL)
620                                         break;
621                         } else
622                                 if (wsi->protocol->name && strcmp(
623                                      wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
624                                                       wsi->protocol->name) == 0)
625                                         break;
626
627                         wsi->protocol++;
628                 }
629
630                 /* we didn't find a protocol he wanted? */
631
632                 if (wsi->protocol->callback == NULL) {
633                         if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL)
634                                 fprintf(stderr, "[no protocol] "
635                                         "not supported (use NULL .name)\n");
636                         else
637                                 fprintf(stderr, "Requested protocol %s "
638                                                 "not supported\n",
639                                      wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
640                         goto bail;
641                 }
642
643                 /*
644                  * find out which spec version the client is using
645                  * if this header is not given, we default to 00 (aka 76)
646                  */
647
648                 if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len)
649                         wsi->ietf_spec_revision =
650                                  atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token);
651
652                 /*
653                  * Give the user code a chance to study the request and
654                  * have the opportunity to deny it
655                  */
656
657                 if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
658                                 LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
659                                                 &wsi->utf8_token[0], NULL, 0)) {
660                         fprintf(stderr, "User code denied connection\n");
661                         goto bail;
662                 }
663
664
665                 /*
666                  * Perform the handshake according to the protocol version the
667                  * client announced
668                  */
669
670                 switch (wsi->ietf_spec_revision) {
671                 case 0: /* applies to 76 and 00 */
672                         wsi->xor_mask = xor_no_mask;
673                         if (handshake_00(context, wsi))
674                                 goto bail;
675                         break;
676                 case 4: /* 04 */
677                         wsi->xor_mask = xor_mask_04;
678                         debug("libwebsocket_parse calling handshake_04\n");
679                         if (handshake_0405(context, wsi))
680                                 goto bail;
681                         break;
682                 case 5:
683                 case 6:
684                 case 7:
685                 case 8:
686                 case 13:
687                         wsi->xor_mask = xor_mask_05;
688                         debug("libwebsocket_parse calling handshake_04\n");
689                         if (handshake_0405(context, wsi))
690                                 goto bail;
691                         break;
692
693                 default:
694                         fprintf(stderr, "Unknown client spec version %d\n",
695                                                        wsi->ietf_spec_revision);
696                         goto bail;
697                 }
698
699                 debug("accepted v%02d connection\n",
700                                                        wsi->ietf_spec_revision);
701
702                 break;
703
704         case WSI_STATE_AWAITING_CLOSE_ACK:
705         case WSI_STATE_ESTABLISHED:
706                 switch (wsi->mode) {
707                 case LWS_CONNMODE_WS_CLIENT:
708                         for (n = 0; n < len; n++)
709                                 if (libwebsocket_client_rx_sm(wsi, *buf++) < 0)
710                                         goto bail;
711
712                         return 0;
713                 default:
714                         break;
715                 }
716
717                 /* LWS_CONNMODE_WS_SERVING */
718
719                 if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0)
720                         goto bail;
721
722                 break;
723         default:
724                 break;
725         }
726
727         return 0;
728
729 bail:
730         libwebsocket_close_and_free_session(context, wsi,
731                                                      LWS_CLOSE_STATUS_NOSTATUS);
732
733         return -1;
734 }