blob: 72e91b29d4d1d27b76020abc102a24b3c230bd97 [file] [log] [blame]
Andy Green76f61e72013-01-16 11:53:05 +08001/*
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#ifdef WIN32
25#include <io.h>
26#endif
27
28int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
29{
30 int n;
31 unsigned char buf[20 + 4];
32 int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
33 int handled;
34 struct lws_tokens eff_buf;
35 int m;
36
37 lwsl_parser(" CRX: %02X %d\n", c, wsi->lws_rx_parse_state);
38
39 switch (wsi->lws_rx_parse_state) {
40 case LWS_RXPS_NEW:
41
42 switch (wsi->ietf_spec_revision) {
43 /* Firefox 4.0b6 likes this as of 30 Oct */
44 case 0:
45 if (c == 0xff)
46 wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
47 if (c == 0) {
48 wsi->lws_rx_parse_state =
49 LWS_RXPS_EAT_UNTIL_76_FF;
50 wsi->rx_user_buffer_head = 0;
51 }
52 break;
53 case 4:
54 case 5:
55 case 6:
56 case 7:
57 case 8:
58 case 13:
59 /*
60 * 04 logical framing from the spec (all this is masked when
61 * incoming and has to be unmasked)
62 *
63 * We ignore the possibility of extension data because we don't
64 * negotiate any extensions at the moment.
65 *
66 * 0 1 2 3
67 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
68 * +-+-+-+-+-------+-+-------------+-------------------------------+
69 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
70 * |I|S|S|S| (4) |S| (7) | (16/63) |
71 * |N|V|V|V| |V| | (if payload len==126/127) |
72 * | |1|2|3| |4| | |
73 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
74 * | Extended payload length continued, if payload len == 127 |
75 * + - - - - - - - - - - - - - - - +-------------------------------+
76 * | | Extension data |
77 * +-------------------------------+ - - - - - - - - - - - - - - - +
78 * : :
79 * +---------------------------------------------------------------+
80 * : Application data :
81 * +---------------------------------------------------------------+
82 *
83 * We pass payload through to userland as soon as we get it, ignoring
84 * FIN. It's up to userland to buffer it up if it wants to see a
85 * whole unfragmented block of the original size (which may be up to
86 * 2^63 long!)
87 *
88 * Notice in v7 RSV4 is set to indicate 32-bit frame key is coming in
89 * after length, unlike extension data which is now deprecated, this
90 * does not impact the payload length calculation.
91 */
92
93 /*
94 * 04 spec defines the opcode like this: (1, 2, and 3 are
95 * "control frame" opcodes which may not be fragmented or
96 * have size larger than 126)
97 *
98 * frame-opcode =
99 * %x0 ; continuation frame
100 * / %x1 ; connection close
101 * / %x2 ; ping
102 * / %x3 ; pong
103 * / %x4 ; text frame
104 * / %x5 ; binary frame
105 * / %x6-F ; reserved
106 *
107 * FIN (b7)
108 */
109
110 if (wsi->ietf_spec_revision < 7)
111 switch (c & 0xf) {
112 case LWS_WS_OPCODE_04__CONTINUATION:
113 wsi->opcode =
114 LWS_WS_OPCODE_07__CONTINUATION;
115 break;
116 case LWS_WS_OPCODE_04__CLOSE:
117 wsi->opcode = LWS_WS_OPCODE_07__CLOSE;
118 break;
119 case LWS_WS_OPCODE_04__PING:
120 wsi->opcode = LWS_WS_OPCODE_07__PING;
121 break;
122 case LWS_WS_OPCODE_04__PONG:
123 wsi->opcode = LWS_WS_OPCODE_07__PONG;
124 break;
125 case LWS_WS_OPCODE_04__TEXT_FRAME:
126 wsi->opcode =
127 LWS_WS_OPCODE_07__TEXT_FRAME;
128 break;
129 case LWS_WS_OPCODE_04__BINARY_FRAME:
130 wsi->opcode =
131 LWS_WS_OPCODE_07__BINARY_FRAME;
132 break;
133 default:
134 lwsl_warn("reserved opcodes not "
135 "usable pre v7 protocol\n");
136 return -1;
137 }
138 else
139 wsi->opcode = c & 0xf;
140 wsi->rsv = (c & 0x70);
141 wsi->final = !!((c >> 7) & 1);
142
143 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
144 break;
145
146 default:
147 lwsl_err("client_rx_sm doesn't know how "
148 "to handle spec version %02d\n",
149 wsi->ietf_spec_revision);
150 break;
151 }
152 break;
153
154
155 case LWS_RXPS_04_FRAME_HDR_LEN:
156
157 if ((c & 0x80) && wsi->ietf_spec_revision < 7) {
158 lwsl_warn("Frame has extensions set illegally 4\n");
159 /* kill the connection */
160 return -1;
161 }
162
163 wsi->this_frame_masked = !!(c & 0x80);
164
165 switch (c & 0x7f) {
166 case 126:
167 /* control frames are not allowed to have big lengths */
168 if (wsi->opcode & 8)
169 goto illegal_ctl_length;
170 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
171 break;
172 case 127:
173 /* control frames are not allowed to have big lengths */
174 if (wsi->opcode & 8)
175 goto illegal_ctl_length;
176 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
177 break;
178 default:
179 wsi->rx_packet_length = c;
180 if (wsi->this_frame_masked)
181 wsi->lws_rx_parse_state =
182 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
183 else {
184 if (c)
185 wsi->lws_rx_parse_state =
186 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
187 else {
188 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
189 goto spill;
190 }
191 }
192 break;
193 }
194 break;
195
196 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
197 wsi->rx_packet_length = c << 8;
198 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
199 break;
200
201 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
202 wsi->rx_packet_length |= c;
203 if (wsi->this_frame_masked)
204 wsi->lws_rx_parse_state =
205 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
206 else {
207 if (wsi->rx_packet_length)
208 wsi->lws_rx_parse_state =
209 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
210 else {
211 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
212 goto spill;
213 }
214 }
215 break;
216
217 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
218 if (c & 0x80) {
219 lwsl_warn("b63 of length must be zero\n");
220 /* kill the connection */
221 return -1;
222 }
223#if defined __LP64__
224 wsi->rx_packet_length = ((size_t)c) << 56;
225#else
226 wsi->rx_packet_length = 0;
227#endif
228 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
229 break;
230
231 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
232#if defined __LP64__
233 wsi->rx_packet_length |= ((size_t)c) << 48;
234#endif
235 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
236 break;
237
238 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
239#if defined __LP64__
240 wsi->rx_packet_length |= ((size_t)c) << 40;
241#endif
242 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
243 break;
244
245 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
246#if defined __LP64__
247 wsi->rx_packet_length |= ((size_t)c) << 32;
248#endif
249 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
250 break;
251
252 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
253 wsi->rx_packet_length |= ((size_t)c) << 24;
254 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
255 break;
256
257 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
258 wsi->rx_packet_length |= ((size_t)c) << 16;
259 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
260 break;
261
262 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
263 wsi->rx_packet_length |= ((size_t)c) << 8;
264 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
265 break;
266
267 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
268 wsi->rx_packet_length |= (size_t)c;
269 if (wsi->this_frame_masked)
270 wsi->lws_rx_parse_state =
271 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
272 else {
273 if (wsi->rx_packet_length)
274 wsi->lws_rx_parse_state =
275 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
276 else {
277 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
278 goto spill;
279 }
280 }
281 break;
282
283 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
284 wsi->frame_masking_nonce_04[0] = c;
285 if (c)
286 wsi->all_zero_nonce = 0;
287 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
288 break;
289
290 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
291 wsi->frame_masking_nonce_04[1] = c;
292 if (c)
293 wsi->all_zero_nonce = 0;
294 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
295 break;
296
297 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
298 wsi->frame_masking_nonce_04[2] = c;
299 if (c)
300 wsi->all_zero_nonce = 0;
301 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
302 break;
303
304 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
305 wsi->frame_masking_nonce_04[3] = c;
306 if (c)
307 wsi->all_zero_nonce = 0;
308
309 if (wsi->rx_packet_length)
310 wsi->lws_rx_parse_state =
311 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
312 else {
313 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
314 goto spill;
315 }
316 break;
317
318 case LWS_RXPS_EAT_UNTIL_76_FF:
319 if (c == 0xff) {
320 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
321 goto issue;
322 }
323 wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
324 (wsi->rx_user_buffer_head++)] = c;
325
326 if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
327 break;
328issue:
329 if (wsi->protocol->callback)
330 wsi->protocol->callback(wsi->protocol->owning_server,
331 wsi,
332 LWS_CALLBACK_CLIENT_RECEIVE,
333 wsi->user_space,
334 &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
335 wsi->rx_user_buffer_head);
336 wsi->rx_user_buffer_head = 0;
337 break;
338 case LWS_RXPS_SEEN_76_FF:
339 if (c)
340 break;
341
342 lwsl_parser("Seen that client is requesting "
343 "a v76 close, sending ack\n");
344 buf[0] = 0xff;
345 buf[1] = 0;
346 n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP);
347 if (n < 0) {
348 lwsl_warn("LWS_RXPS_SEEN_76_FF: ERROR writing to socket\n");
349 return -1;
350 }
351 lwsl_parser(" v76 close ack sent, server closing skt\n");
352 /* returning < 0 will get it closed in parent */
353 return -1;
354
355 case LWS_RXPS_PULLING_76_LENGTH:
356 break;
357
358 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
359 if ((!wsi->this_frame_masked) || wsi->all_zero_nonce)
360 wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
361 (wsi->rx_user_buffer_head++)] = c;
362 else
363 wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
364 (wsi->rx_user_buffer_head++)] =
365 wsi->xor_mask(wsi, c);
366
367 if (--wsi->rx_packet_length == 0) {
368 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
369 goto spill;
370 }
371 if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
372 break;
373spill:
374
375 handled = 0;
376
377 /*
378 * is this frame a control packet we should take care of at this
379 * layer? If so service it and hide it from the user callback
380 */
381
382 switch (wsi->opcode) {
383 case LWS_WS_OPCODE_07__CLOSE:
384 /* is this an acknowledgement of our close? */
385 if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
386 /*
387 * fine he has told us he is closing too, let's
388 * finish our close
389 */
390 lwsl_parser("seen server's close ack\n");
391 return -1;
392 }
393 lwsl_parser("client sees server close packet len = %d\n", wsi->rx_user_buffer_head);
394 /* parrot the close packet payload back */
395 n = libwebsocket_write(wsi, (unsigned char *)
396 &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
397 wsi->rx_user_buffer_head, LWS_WRITE_CLOSE);
398 lwsl_parser("client writing close ack returned %d\n", n);
399 wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
400 /* close the connection */
401 return -1;
402
403 case LWS_WS_OPCODE_07__PING:
404 /* parrot the ping packet payload back as a pong*/
405 n = libwebsocket_write(wsi, (unsigned char *)
406 &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
407 wsi->rx_user_buffer_head, LWS_WRITE_PONG);
408 handled = 1;
409 break;
410
411 case LWS_WS_OPCODE_07__PONG:
412 /* keep the statistics... */
413 wsi->pings_vs_pongs--;
414
415 /* issue it */
416 callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
417 break;
418
419 case LWS_WS_OPCODE_07__CONTINUATION:
420 case LWS_WS_OPCODE_07__TEXT_FRAME:
421 case LWS_WS_OPCODE_07__BINARY_FRAME:
422 break;
423
424 default:
425
426 lwsl_parser("Reserved opcode 0x%2X\n", wsi->opcode);
427 /*
428 * It's something special we can't understand here.
429 * Pass the payload up to the extension's parsing
430 * state machine.
431 */
432
433 eff_buf.token = &wsi->rx_user_buffer[
434 LWS_SEND_BUFFER_PRE_PADDING];
435 eff_buf.token_len = wsi->rx_user_buffer_head;
436
437 for (n = 0; n < wsi->count_active_extensions; n++) {
438 m = wsi->active_extensions[n]->callback(
439 wsi->protocol->owning_server,
440 wsi->active_extensions[n], wsi,
441 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
442 wsi->active_extensions_user[n],
443 &eff_buf, 0);
444 if (m)
445 handled = 1;
446 }
447
448 if (!handled) {
449 lwsl_ext("Unhandled extended opcode "
450 "0x%x - ignoring frame\n", wsi->opcode);
451 wsi->rx_user_buffer_head = 0;
452
453 return 0;
454 }
455
456 break;
457 }
458
459 /*
460 * No it's real payload, pass it up to the user callback.
461 * It's nicely buffered with the pre-padding taken care of
462 * so it can be sent straight out again using libwebsocket_write
463 */
464 if (handled)
465 goto already_done;
466
467 eff_buf.token = &wsi->rx_user_buffer[
468 LWS_SEND_BUFFER_PRE_PADDING];
469 eff_buf.token_len = wsi->rx_user_buffer_head;
470
471 for (n = 0; n < wsi->count_active_extensions; n++) {
472 m = wsi->active_extensions[n]->callback(
473 wsi->protocol->owning_server,
474 wsi->active_extensions[n], wsi,
475 LWS_EXT_CALLBACK_PAYLOAD_RX,
476 wsi->active_extensions_user[n],
477 &eff_buf, 0);
478 if (m < 0) {
479 lwsl_ext(
480 "Extension '%s' failed to handle payload!\n",
481 wsi->active_extensions[n]->name);
482 return -1;
483 }
484 }
485
486 if (eff_buf.token_len > 0) {
487 eff_buf.token[eff_buf.token_len] = '\0';
488
489 if (wsi->protocol->callback)
490 wsi->protocol->callback(
491 wsi->protocol->owning_server,
492 wsi,
493 (enum libwebsocket_callback_reasons)callback_action,
494 wsi->user_space,
495 eff_buf.token,
496 eff_buf.token_len);
497 }
498already_done:
499 wsi->rx_user_buffer_head = 0;
500 break;
501 default:
502 lwsl_err("client rx illegal state\n");
503 return 1;
504 }
505
506 return 0;
507
508illegal_ctl_length:
509
510 lwsl_warn("Control frame asking for "
511 "extended length is illegal\n");
512 /* kill the connection */
513 return -1;
514
515}
516
517