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