act on fatal parse problems
[profile/ivi/libwebsockets.git] / lib / client-parser.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 int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
25 {
26         int n;
27         int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
28         int handled;
29         struct lws_tokens eff_buf;
30 #ifndef LWS_NO_EXTENSIONS
31         int m;
32 #endif
33
34 //      lwsl_parser(" CRX: %02X %d\n", c, wsi->lws_rx_parse_state);
35
36         switch (wsi->lws_rx_parse_state) {
37         case LWS_RXPS_NEW:
38
39                 switch (wsi->ietf_spec_revision) {
40
41                 case 13:
42                         wsi->u.ws.opcode = c & 0xf;
43                         wsi->u.ws.rsv = (c & 0x70);
44                         wsi->u.ws.final = !!((c >> 7) & 1);
45                         switch (wsi->u.ws.opcode) {
46                         case LWS_WS_OPCODE_07__TEXT_FRAME:
47                         case LWS_WS_OPCODE_07__BINARY_FRAME:
48                                 wsi->u.ws.frame_is_binary = wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME;
49                                 break;
50                         }
51                         wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
52                         break;
53
54                 default:
55                         lwsl_err("client_rx_sm doesn't know how "
56                                 "to handle spec version %02d\n",
57                                                        wsi->ietf_spec_revision);
58                         break;
59                 }
60                 break;
61
62
63         case LWS_RXPS_04_FRAME_HDR_LEN:
64
65                 wsi->u.ws.this_frame_masked = !!(c & 0x80);
66
67                 switch (c & 0x7f) {
68                 case 126:
69                         /* control frames are not allowed to have big lengths */
70                         if (wsi->u.ws.opcode & 8)
71                                 goto illegal_ctl_length;
72                         wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
73                         break;
74                 case 127:
75                         /* control frames are not allowed to have big lengths */
76                         if (wsi->u.ws.opcode & 8)
77                                 goto illegal_ctl_length;
78                         wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
79                         break;
80                 default:
81                         wsi->u.ws.rx_packet_length = c;
82                         if (wsi->u.ws.this_frame_masked)
83                                 wsi->lws_rx_parse_state =
84                                                 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
85                         else {
86                                 if (c)
87                                         wsi->lws_rx_parse_state =
88                                         LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
89                                 else {
90                                         wsi->lws_rx_parse_state = LWS_RXPS_NEW;
91                                         goto spill;
92                                 }
93                         }
94                         break;
95                 }
96                 break;
97
98         case LWS_RXPS_04_FRAME_HDR_LEN16_2:
99                 wsi->u.ws.rx_packet_length = c << 8;
100                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
101                 break;
102
103         case LWS_RXPS_04_FRAME_HDR_LEN16_1:
104                 wsi->u.ws.rx_packet_length |= c;
105                 if (wsi->u.ws.this_frame_masked)
106                         wsi->lws_rx_parse_state =
107                                         LWS_RXPS_07_COLLECT_FRAME_KEY_1;
108                 else {
109                         if (wsi->u.ws.rx_packet_length)
110                                 wsi->lws_rx_parse_state =
111                                         LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
112                         else {
113                                 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
114                                 goto spill;
115                         }
116                 }
117                 break;
118
119         case LWS_RXPS_04_FRAME_HDR_LEN64_8:
120                 if (c & 0x80) {
121                         lwsl_warn("b63 of length must be zero\n");
122                         /* kill the connection */
123                         return -1;
124                 }
125 #if defined __LP64__
126                 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
127 #else
128                 wsi->u.ws.rx_packet_length = 0;
129 #endif
130                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
131                 break;
132
133         case LWS_RXPS_04_FRAME_HDR_LEN64_7:
134 #if defined __LP64__
135                 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
136 #endif
137                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
138                 break;
139
140         case LWS_RXPS_04_FRAME_HDR_LEN64_6:
141 #if defined __LP64__
142                 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
143 #endif
144                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
145                 break;
146
147         case LWS_RXPS_04_FRAME_HDR_LEN64_5:
148 #if defined __LP64__
149                 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
150 #endif
151                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
152                 break;
153
154         case LWS_RXPS_04_FRAME_HDR_LEN64_4:
155                 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
156                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
157                 break;
158
159         case LWS_RXPS_04_FRAME_HDR_LEN64_3:
160                 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
161                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
162                 break;
163
164         case LWS_RXPS_04_FRAME_HDR_LEN64_2:
165                 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
166                 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
167                 break;
168
169         case LWS_RXPS_04_FRAME_HDR_LEN64_1:
170                 wsi->u.ws.rx_packet_length |= (size_t)c;
171                 if (wsi->u.ws.this_frame_masked)
172                         wsi->lws_rx_parse_state =
173                                         LWS_RXPS_07_COLLECT_FRAME_KEY_1;
174                 else {
175                         if (wsi->u.ws.rx_packet_length)
176                                 wsi->lws_rx_parse_state =
177                                         LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
178                         else {
179                                 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
180                                 goto spill;
181                         }
182                 }
183                 break;
184
185         case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
186                 wsi->u.ws.frame_masking_nonce_04[0] = c;
187                 if (c)
188                         wsi->u.ws.all_zero_nonce = 0;
189                 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
190                 break;
191
192         case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
193                 wsi->u.ws.frame_masking_nonce_04[1] = c;
194                 if (c)
195                         wsi->u.ws.all_zero_nonce = 0;
196                 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
197                 break;
198
199         case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
200                 wsi->u.ws.frame_masking_nonce_04[2] = c;
201                 if (c)
202                         wsi->u.ws.all_zero_nonce = 0;
203                 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
204                 break;
205
206         case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
207                 wsi->u.ws.frame_masking_nonce_04[3] = c;
208                 if (c)
209                         wsi->u.ws.all_zero_nonce = 0;
210
211                 if (wsi->u.ws.rx_packet_length)
212                         wsi->lws_rx_parse_state =
213                                         LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
214                 else {
215                         wsi->lws_rx_parse_state = LWS_RXPS_NEW;
216                         goto spill;
217                 }
218                 break;
219
220         case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
221                 if ((!wsi->u.ws.this_frame_masked) || wsi->u.ws.all_zero_nonce)
222                         wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
223                                (wsi->u.ws.rx_user_buffer_head++)] = c;
224                 else
225                         wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
226                                (wsi->u.ws.rx_user_buffer_head++)] =
227                         c ^ wsi->u.ws.frame_masking_nonce_04[(wsi->u.ws.frame_mask_index++) & 3];
228
229                 if (--wsi->u.ws.rx_packet_length == 0) {
230                         wsi->lws_rx_parse_state = LWS_RXPS_NEW;
231                         goto spill;
232                 }
233                 if (wsi->u.ws.rx_user_buffer_head != MAX_USER_RX_BUFFER)
234                         break;
235 spill:
236
237                 handled = 0;
238
239                 /*
240                  * is this frame a control packet we should take care of at this
241                  * layer?  If so service it and hide it from the user callback
242                  */
243
244                 switch (wsi->u.ws.opcode) {
245                 case LWS_WS_OPCODE_07__CLOSE:
246                         /* is this an acknowledgement of our close? */
247                         if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
248                                 /*
249                                  * fine he has told us he is closing too, let's
250                                  * finish our close
251                                  */
252                                 lwsl_parser("seen server's close ack\n");
253                                 return -1;
254                         }
255                         lwsl_parser("client sees server close packet len = %d\n", wsi->u.ws.rx_user_buffer_head);
256                         /* parrot the close packet payload back */
257                         n = libwebsocket_write(wsi, (unsigned char *)
258                            &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
259                                      wsi->u.ws.rx_user_buffer_head, LWS_WRITE_CLOSE);
260                         lwsl_parser("client writing close ack returned %d\n", n);
261                         wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
262                         /* close the connection */
263                         return -1;
264
265                 case LWS_WS_OPCODE_07__PING:
266                         lwsl_info("client received ping, doing pong\n");
267                         /* parrot the ping packet payload back as a pong*/
268                         n = libwebsocket_write(wsi, (unsigned char *)
269                             &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
270                                     wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG);
271                         handled = 1;
272                         break;
273
274                 case LWS_WS_OPCODE_07__PONG:
275                         lwsl_info("client receied pong\n");
276                         lwsl_hexdump(&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
277                                     wsi->u.ws.rx_user_buffer_head);
278                         /* keep the statistics... */
279                         wsi->u.ws.pings_vs_pongs--;
280
281                         /* issue it */
282                         callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
283                         break;
284
285                 case LWS_WS_OPCODE_07__CONTINUATION:
286                 case LWS_WS_OPCODE_07__TEXT_FRAME:
287                 case LWS_WS_OPCODE_07__BINARY_FRAME:
288                         break;
289
290                 default:
291
292                         lwsl_parser("Reserved opcode 0x%2X\n", wsi->u.ws.opcode);
293 #ifndef LWS_NO_EXTENSIONS
294                         /*
295                          * It's something special we can't understand here.
296                          * Pass the payload up to the extension's parsing
297                          * state machine.
298                          */
299
300                         eff_buf.token = &wsi->u.ws.rx_user_buffer[
301                                                    LWS_SEND_BUFFER_PRE_PADDING];
302                         eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
303
304                         for (n = 0; n < wsi->count_active_extensions; n++) {
305                                 m = wsi->active_extensions[n]->callback(
306                                         wsi->protocol->owning_server,
307                                         wsi->active_extensions[n], wsi,
308                                         LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
309                                             wsi->active_extensions_user[n],
310                                                                    &eff_buf, 0);
311                                 if (m)
312                                         handled = 1;
313                         }
314
315                         if (!handled) {
316 #else
317                         {
318 #endif
319                                 lwsl_ext("Unhandled extended opcode "
320                                         "0x%x - ignoring frame\n", wsi->u.ws.opcode);
321                                 wsi->u.ws.rx_user_buffer_head = 0;
322
323                                 return 0;
324                         }
325
326                         break;
327                 }
328
329                 /*
330                  * No it's real payload, pass it up to the user callback.
331                  * It's nicely buffered with the pre-padding taken care of
332                  * so it can be sent straight out again using libwebsocket_write
333                  */
334                 if (handled)
335                         goto already_done;
336
337                 eff_buf.token = &wsi->u.ws.rx_user_buffer[
338                                                 LWS_SEND_BUFFER_PRE_PADDING];
339                 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
340 #ifndef LWS_NO_EXTENSIONS
341                 for (n = 0; n < wsi->count_active_extensions; n++) {
342                         m = wsi->active_extensions[n]->callback(
343                                 wsi->protocol->owning_server,
344                                 wsi->active_extensions[n], wsi,
345                                 LWS_EXT_CALLBACK_PAYLOAD_RX,
346                                 wsi->active_extensions_user[n],
347                                 &eff_buf, 0);
348                         if (m < 0) {
349                                 lwsl_ext(
350                                         "Extension '%s' failed to handle payload!\n",
351                                                 wsi->active_extensions[n]->name);
352                                 return -1;
353                         }
354                 }
355 #endif
356                 if (eff_buf.token_len > 0) {
357                         eff_buf.token[eff_buf.token_len] = '\0';
358
359                         if (wsi->protocol->callback) {
360                                 if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
361                                         lwsl_info("Client doing pong callback\n");
362                                 wsi->protocol->callback(
363                                                 wsi->protocol->owning_server,
364                                                 wsi,
365                         (enum libwebsocket_callback_reasons)callback_action,
366                                                 wsi->user_space,
367                                                 eff_buf.token,
368                                                 eff_buf.token_len);
369                         }
370                 }
371 already_done:
372                 wsi->u.ws.rx_user_buffer_head = 0;
373                 break;
374         default:
375                 lwsl_err("client rx illegal state\n");
376                 return 1;
377         }
378
379         return 0;
380
381 illegal_ctl_length:
382
383         lwsl_warn("Control frame asking for "
384                                 "extended length is illegal\n");
385         /* kill the connection */
386         return -1;
387
388 }
389
390