2 * libwebsockets - small server side websockets and web server implementation
4 * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
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.
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.
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,
22 #include "private-libwebsockets.h"
24 int lws_client_rx_sm(struct lws *wsi, unsigned char c)
26 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
27 int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
28 int handled, n, m, rx_draining_ext = 0;
29 unsigned short close_code;
30 struct lws_tokens eff_buf;
33 if (wsi->u.ws.rx_draining_ext) {
34 struct lws **w = &pt->rx_draining_ext_list;
35 lwsl_ext("%s: RX EXT DRAINING: Removing from list\n", __func__, c);
38 eff_buf.token_len = 0;
39 wsi->u.ws.rx_draining_ext = 0;
40 /* remove us from context draining ext list */
43 *w = wsi->u.ws.rx_draining_ext_list;
46 w = &((*w)->u.ws.rx_draining_ext_list);
48 wsi->u.ws.rx_draining_ext_list = NULL;
54 switch (wsi->lws_rx_parse_state) {
56 /* control frames (PING) may interrupt checkable sequences */
57 wsi->u.ws.defeat_check_utf8 = 0;
59 switch (wsi->ietf_spec_revision) {
61 wsi->u.ws.opcode = c & 0xf;
62 /* revisit if an extension wants them... */
63 switch (wsi->u.ws.opcode) {
64 case LWSWSOPC_TEXT_FRAME:
65 wsi->u.ws.rsv_first_msg = (c & 0x70);
66 wsi->u.ws.continuation_possible = 1;
67 wsi->u.ws.check_utf8 =
68 !!(wsi->context->options &
69 LWS_SERVER_OPTION_VALIDATE_UTF8);
72 case LWSWSOPC_BINARY_FRAME:
73 wsi->u.ws.rsv_first_msg = (c & 0x70);
74 wsi->u.ws.check_utf8 = 0;
75 wsi->u.ws.continuation_possible = 1;
77 case LWSWSOPC_CONTINUATION:
78 if (!wsi->u.ws.continuation_possible) {
79 lwsl_info("disordered continuation\n");
84 wsi->u.ws.check_utf8 = 0;
97 lwsl_info("illegal opcode\n");
100 wsi->u.ws.defeat_check_utf8 = 1;
103 wsi->u.ws.rsv = (c & 0x70);
104 /* revisit if an extension wants them... */
106 #ifndef LWS_NO_EXTENSIONS
107 !wsi->count_act_ext &&
110 lwsl_info("illegal rsv bits set\n");
113 wsi->u.ws.final = !!((c >> 7) & 1);
114 lwsl_ext("%s: This RX frame Final %d\n", __func__, wsi->u.ws.final);
116 if (wsi->u.ws.owed_a_fin &&
117 (wsi->u.ws.opcode == LWSWSOPC_TEXT_FRAME ||
118 wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME)) {
119 lwsl_info("hey you owed us a FIN\n");
122 if ((!(wsi->u.ws.opcode & 8)) && wsi->u.ws.final) {
123 wsi->u.ws.continuation_possible = 0;
124 wsi->u.ws.owed_a_fin = 0;
127 if ((wsi->u.ws.opcode & 8) && !wsi->u.ws.final) {
128 lwsl_info("control message cannot be fragmented\n");
131 if (!wsi->u.ws.final)
132 wsi->u.ws.owed_a_fin = 1;
134 switch (wsi->u.ws.opcode) {
135 case LWSWSOPC_TEXT_FRAME:
136 case LWSWSOPC_BINARY_FRAME:
137 wsi->u.ws.frame_is_binary = wsi->u.ws.opcode ==
138 LWSWSOPC_BINARY_FRAME;
141 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
145 lwsl_err("unknown spec version %02d\n",
146 wsi->ietf_spec_revision);
151 case LWS_RXPS_04_FRAME_HDR_LEN:
153 wsi->u.ws.this_frame_masked = !!(c & 0x80);
157 /* control frames are not allowed to have big lengths */
158 if (wsi->u.ws.opcode & 8)
159 goto illegal_ctl_length;
160 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
163 /* control frames are not allowed to have big lengths */
164 if (wsi->u.ws.opcode & 8)
165 goto illegal_ctl_length;
166 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
169 wsi->u.ws.rx_packet_length = c;
170 if (wsi->u.ws.this_frame_masked)
171 wsi->lws_rx_parse_state =
172 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
175 wsi->lws_rx_parse_state =
176 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
178 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
186 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
187 wsi->u.ws.rx_packet_length = c << 8;
188 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
191 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
192 wsi->u.ws.rx_packet_length |= c;
193 if (wsi->u.ws.this_frame_masked)
194 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1;
196 if (wsi->u.ws.rx_packet_length)
197 wsi->lws_rx_parse_state =
198 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
200 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
206 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
208 lwsl_warn("b63 of length must be zero\n");
209 /* kill the connection */
213 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
215 wsi->u.ws.rx_packet_length = 0;
217 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
220 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
222 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
224 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
227 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
229 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
231 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
234 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
236 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
238 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
241 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
242 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
243 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
246 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
247 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
248 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
251 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
252 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
253 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
256 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
257 wsi->u.ws.rx_packet_length |= (size_t)c;
258 if (wsi->u.ws.this_frame_masked)
259 wsi->lws_rx_parse_state =
260 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
262 if (wsi->u.ws.rx_packet_length)
263 wsi->lws_rx_parse_state =
264 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
266 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
272 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
273 wsi->u.ws.mask[0] = c;
275 wsi->u.ws.all_zero_nonce = 0;
276 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
279 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
280 wsi->u.ws.mask[1] = c;
282 wsi->u.ws.all_zero_nonce = 0;
283 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
286 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
287 wsi->u.ws.mask[2] = c;
289 wsi->u.ws.all_zero_nonce = 0;
290 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
293 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
294 wsi->u.ws.mask[3] = c;
296 wsi->u.ws.all_zero_nonce = 0;
298 if (wsi->u.ws.rx_packet_length)
299 wsi->lws_rx_parse_state =
300 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
302 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
307 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
309 assert(wsi->u.ws.rx_ubuf);
311 if (wsi->u.ws.this_frame_masked && !wsi->u.ws.all_zero_nonce)
312 c ^= wsi->u.ws.mask[(wsi->u.ws.mask_idx++) & 3];
314 wsi->u.ws.rx_ubuf[LWS_PRE + (wsi->u.ws.rx_ubuf_head++)] = c;
316 if (--wsi->u.ws.rx_packet_length == 0) {
317 /* spill because we have the whole frame */
318 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
323 * if there's no protocol max frame size given, we are
324 * supposed to default to LWS_MAX_SOCKET_IO_BUF
326 if (!wsi->protocol->rx_buffer_size &&
327 wsi->u.ws.rx_ubuf_head != LWS_MAX_SOCKET_IO_BUF)
330 if (wsi->protocol->rx_buffer_size &&
331 wsi->u.ws.rx_ubuf_head != wsi->protocol->rx_buffer_size)
334 /* spill because we filled our rx buffer */
340 * is this frame a control packet we should take care of at this
341 * layer? If so service it and hide it from the user callback
344 switch (wsi->u.ws.opcode) {
346 pp = (unsigned char *)&wsi->u.ws.rx_ubuf[LWS_PRE];
347 if (wsi->context->options & LWS_SERVER_OPTION_VALIDATE_UTF8 &&
348 wsi->u.ws.rx_ubuf_head > 2 &&
349 lws_check_utf8(&wsi->u.ws.utf8, pp + 2,
350 wsi->u.ws.rx_ubuf_head - 2))
353 /* is this an acknowledgement of our close? */
354 if (wsi->state == LWSS_AWAITING_CLOSE_ACK) {
356 * fine he has told us he is closing too, let's
359 lwsl_parser("seen server's close ack\n");
363 lwsl_parser("client sees server close len = %d\n",
364 wsi->u.ws.rx_ubuf_head);
365 if (wsi->u.ws.rx_ubuf_head >= 2) {
366 close_code = (pp[0] << 8) | pp[1];
367 if (close_code < 1000 || close_code == 1004 ||
368 close_code == 1005 || close_code == 1006 ||
369 close_code == 1012 || close_code == 1013 ||
370 close_code == 1014 || close_code == 1015 ||
371 (close_code >= 1016 && close_code < 3000)
373 pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff;
374 pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff;
377 if (user_callback_handle_rxflow(
378 wsi->protocol->callback, wsi,
379 LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
381 wsi->u.ws.rx_ubuf_head))
384 * parrot the close packet payload back
385 * we do not care about how it went, we are closing
386 * immediately afterwards
388 lws_write(wsi, (unsigned char *)&wsi->u.ws.rx_ubuf[LWS_PRE],
389 wsi->u.ws.rx_ubuf_head, LWS_WRITE_CLOSE);
390 wsi->state = LWSS_RETURNED_CLOSE_ALREADY;
391 /* close the connection */
395 lwsl_info("received %d byte ping, sending pong\n",
396 wsi->u.ws.rx_ubuf_head);
398 /* he set a close reason on this guy, ignore PING */
399 if (wsi->u.ws.close_in_ping_buffer_len)
402 if (wsi->u.ws.ping_pending_flag) {
404 * there is already a pending ping payload
405 * we should just log and drop
407 lwsl_parser("DROP PING since one pending\n");
411 /* control packets can only be < 128 bytes long */
412 if (wsi->u.ws.rx_ubuf_head > 128 - 3) {
413 lwsl_parser("DROP PING payload too large\n");
417 /* stash the pong payload */
418 memcpy(wsi->u.ws.ping_payload_buf + LWS_PRE,
419 &wsi->u.ws.rx_ubuf[LWS_PRE],
420 wsi->u.ws.rx_ubuf_head);
422 wsi->u.ws.ping_payload_len = wsi->u.ws.rx_ubuf_head;
423 wsi->u.ws.ping_pending_flag = 1;
425 /* get it sent as soon as possible */
426 lws_callback_on_writable(wsi);
428 wsi->u.ws.rx_ubuf_head = 0;
433 lwsl_info("client receied pong\n");
434 lwsl_hexdump(&wsi->u.ws.rx_ubuf[LWS_PRE],
435 wsi->u.ws.rx_ubuf_head);
438 callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
441 case LWSWSOPC_CONTINUATION:
442 case LWSWSOPC_TEXT_FRAME:
443 case LWSWSOPC_BINARY_FRAME:
448 lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
451 * It's something special we can't understand here.
452 * Pass the payload up to the extension's parsing
456 eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
457 eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
459 if (lws_ext_cb_active(wsi,
460 LWS_EXT_CB_EXTENDED_PAYLOAD_RX,
461 &eff_buf, 0) <= 0) { /* not handle or fail */
463 lwsl_ext("Unhandled ext opc 0x%x\n", wsi->u.ws.opcode);
464 wsi->u.ws.rx_ubuf_head = 0;
473 * No it's real payload, pass it up to the user callback.
474 * It's nicely buffered with the pre-padding taken care of
475 * so it can be sent straight out again using lws_write
480 eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
481 eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
484 n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0);
485 lwsl_ext("Ext RX returned %d\n", n);
486 if (n < 0) /* fail */
489 lwsl_ext("post inflate eff_buf len %d\n", eff_buf.token_len);
491 if (rx_draining_ext && !eff_buf.token_len) {
492 lwsl_err(" --- ignoring zero drain result, ending drain\n");
496 if (wsi->u.ws.check_utf8 && !wsi->u.ws.defeat_check_utf8) {
497 if (lws_check_utf8(&wsi->u.ws.utf8,
498 (unsigned char *)eff_buf.token,
502 /* we are ending partway through utf-8 character? */
503 if (!wsi->u.ws.rx_packet_length && wsi->u.ws.final && wsi->u.ws.utf8 && !n) {
504 lwsl_info("FINAL utf8 error\n");
505 utf8_fail: lwsl_info("utf8 error\n");
510 if (eff_buf.token_len < 0 &&
511 callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
517 eff_buf.token[eff_buf.token_len] = '\0';
519 if (!wsi->protocol->callback)
522 if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
523 lwsl_info("Client doing pong callback\n");
525 if (n && eff_buf.token_len) {
526 /* extension had more... main loop will come back
527 * we want callback to be done with this set, if so,
528 * because lws_is_final() hides it was final until the
531 wsi->u.ws.rx_draining_ext = 1;
532 wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list;
533 pt->rx_draining_ext_list = wsi;
534 lwsl_ext("%s: RX EXT DRAINING: Adding to list\n", __func__);
536 if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
537 wsi->state == LWSS_AWAITING_CLOSE_ACK)
540 m = wsi->protocol->callback(wsi,
541 (enum lws_callback_reasons)callback_action,
542 wsi->user_space, eff_buf.token, eff_buf.token_len);
544 /* if user code wants to close, let caller know */
549 wsi->u.ws.rx_ubuf_head = 0;
552 lwsl_err("client rx illegal state\n");
559 lwsl_warn("Control frame asking for extended length is illegal\n");
560 /* kill the connection */