ac72f8ff49855cfd4b5f841adc74b56384a3ddcc
[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
222                 if (!wsi->u.ws.rx_user_buffer)
223                         lwsl_err("NULL client rx_user_buffer\n");
224
225                 if ((!wsi->u.ws.this_frame_masked) || wsi->u.ws.all_zero_nonce)
226                         wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
227                                (wsi->u.ws.rx_user_buffer_head++)] = c;
228                 else
229                         wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
230                                (wsi->u.ws.rx_user_buffer_head++)] =
231                         c ^ wsi->u.ws.frame_masking_nonce_04[(wsi->u.ws.frame_mask_index++) & 3];
232
233                 if (--wsi->u.ws.rx_packet_length == 0) {
234                         wsi->lws_rx_parse_state = LWS_RXPS_NEW;
235                         goto spill;
236                 }
237                 if (wsi->u.ws.rx_user_buffer_head != wsi->protocol->rx_buffer_size)
238                         break;
239 spill:
240
241                 handled = 0;
242
243                 /*
244                  * is this frame a control packet we should take care of at this
245                  * layer?  If so service it and hide it from the user callback
246                  */
247
248                 switch (wsi->u.ws.opcode) {
249                 case LWS_WS_OPCODE_07__CLOSE:
250                         /* is this an acknowledgement of our close? */
251                         if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
252                                 /*
253                                  * fine he has told us he is closing too, let's
254                                  * finish our close
255                                  */
256                                 lwsl_parser("seen server's close ack\n");
257                                 return -1;
258                         }
259                         lwsl_parser("client sees server close packet len = %d\n", wsi->u.ws.rx_user_buffer_head);
260                         /* parrot the close packet payload back */
261                         n = libwebsocket_write(wsi, (unsigned char *)
262                            &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
263                                      wsi->u.ws.rx_user_buffer_head, LWS_WRITE_CLOSE);
264                         lwsl_parser("client writing close ack returned %d\n", n);
265                         wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
266                         /* close the connection */
267                         return -1;
268
269                 case LWS_WS_OPCODE_07__PING:
270                         lwsl_info("client received ping, doing pong\n");
271                         /* parrot the ping packet payload back as a pong*/
272                         n = libwebsocket_write(wsi, (unsigned char *)
273                             &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
274                                     wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG);
275                         handled = 1;
276                         break;
277
278                 case LWS_WS_OPCODE_07__PONG:
279                         lwsl_info("client receied pong\n");
280                         lwsl_hexdump(&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
281                                     wsi->u.ws.rx_user_buffer_head);
282                         /* keep the statistics... */
283                         wsi->u.ws.pings_vs_pongs--;
284
285                         /* issue it */
286                         callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
287                         break;
288
289                 case LWS_WS_OPCODE_07__CONTINUATION:
290                 case LWS_WS_OPCODE_07__TEXT_FRAME:
291                 case LWS_WS_OPCODE_07__BINARY_FRAME:
292                         break;
293
294                 default:
295
296                         lwsl_parser("Reserved opcode 0x%2X\n", wsi->u.ws.opcode);
297 #ifndef LWS_NO_EXTENSIONS
298                         /*
299                          * It's something special we can't understand here.
300                          * Pass the payload up to the extension's parsing
301                          * state machine.
302                          */
303
304                         eff_buf.token = &wsi->u.ws.rx_user_buffer[
305                                                    LWS_SEND_BUFFER_PRE_PADDING];
306                         eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
307
308                         for (n = 0; n < wsi->count_active_extensions; n++) {
309                                 m = wsi->active_extensions[n]->callback(
310                                         wsi->protocol->owning_server,
311                                         wsi->active_extensions[n], wsi,
312                                         LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
313                                             wsi->active_extensions_user[n],
314                                                                    &eff_buf, 0);
315                                 if (m)
316                                         handled = 1;
317                         }
318
319                         if (!handled) {
320 #else
321                         {
322 #endif
323                                 lwsl_ext("Unhandled extended opcode "
324                                         "0x%x - ignoring frame\n", wsi->u.ws.opcode);
325                                 wsi->u.ws.rx_user_buffer_head = 0;
326
327                                 return 0;
328                         }
329
330                         break;
331                 }
332
333                 /*
334                  * No it's real payload, pass it up to the user callback.
335                  * It's nicely buffered with the pre-padding taken care of
336                  * so it can be sent straight out again using libwebsocket_write
337                  */
338                 if (handled)
339                         goto already_done;
340
341                 eff_buf.token = &wsi->u.ws.rx_user_buffer[
342                                                 LWS_SEND_BUFFER_PRE_PADDING];
343                 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
344 #ifndef LWS_NO_EXTENSIONS
345                 for (n = 0; n < wsi->count_active_extensions; n++) {
346                         m = wsi->active_extensions[n]->callback(
347                                 wsi->protocol->owning_server,
348                                 wsi->active_extensions[n], wsi,
349                                 LWS_EXT_CALLBACK_PAYLOAD_RX,
350                                 wsi->active_extensions_user[n],
351                                 &eff_buf, 0);
352                         if (m < 0) {
353                                 lwsl_ext(
354                                         "Extension '%s' failed to handle payload!\n",
355                                                 wsi->active_extensions[n]->name);
356                                 return -1;
357                         }
358                 }
359 #endif
360                 if (eff_buf.token_len > 0) {
361                         eff_buf.token[eff_buf.token_len] = '\0';
362
363                         if (wsi->protocol->callback) {
364                                 if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
365                                         lwsl_info("Client doing pong callback\n");
366                                 wsi->protocol->callback(
367                                                 wsi->protocol->owning_server,
368                                                 wsi,
369                         (enum libwebsocket_callback_reasons)callback_action,
370                                                 wsi->user_space,
371                                                 eff_buf.token,
372                                                 eff_buf.token_len);
373                         }
374                 }
375 already_done:
376                 wsi->u.ws.rx_user_buffer_head = 0;
377                 break;
378         default:
379                 lwsl_err("client rx illegal state\n");
380                 return 1;
381         }
382
383         return 0;
384
385 illegal_ctl_length:
386
387         lwsl_warn("Control frame asking for "
388                                 "extended length is illegal\n");
389         /* kill the connection */
390         return -1;
391
392 }
393
394