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 = lws_check_opt(
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 (lws_check_opt(wsi->context->options,
348 LWS_SERVER_OPTION_VALIDATE_UTF8) &&
349 wsi->u.ws.rx_ubuf_head > 2 &&
350 lws_check_utf8(&wsi->u.ws.utf8, pp + 2,
351 wsi->u.ws.rx_ubuf_head - 2))
354 /* is this an acknowledgement of our close? */
355 if (wsi->state == LWSS_AWAITING_CLOSE_ACK) {
357 * fine he has told us he is closing too, let's
360 lwsl_parser("seen server's close ack\n");
364 lwsl_parser("client sees server close len = %d\n",
365 wsi->u.ws.rx_ubuf_head);
366 if (wsi->u.ws.rx_ubuf_head >= 2) {
367 close_code = (pp[0] << 8) | pp[1];
368 if (close_code < 1000 || close_code == 1004 ||
369 close_code == 1005 || close_code == 1006 ||
370 close_code == 1012 || close_code == 1013 ||
371 close_code == 1014 || close_code == 1015 ||
372 (close_code >= 1016 && close_code < 3000)
374 pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff;
375 pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff;
378 if (user_callback_handle_rxflow(
379 wsi->protocol->callback, wsi,
380 LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
382 wsi->u.ws.rx_ubuf_head))
385 * parrot the close packet payload back
386 * we do not care about how it went, we are closing
387 * immediately afterwards
389 lws_write(wsi, (unsigned char *)&wsi->u.ws.rx_ubuf[LWS_PRE],
390 wsi->u.ws.rx_ubuf_head, LWS_WRITE_CLOSE);
391 wsi->state = LWSS_RETURNED_CLOSE_ALREADY;
392 /* close the connection */
396 lwsl_info("received %d byte ping, sending pong\n",
397 wsi->u.ws.rx_ubuf_head);
399 /* he set a close reason on this guy, ignore PING */
400 if (wsi->u.ws.close_in_ping_buffer_len)
403 if (wsi->u.ws.ping_pending_flag) {
405 * there is already a pending ping payload
406 * we should just log and drop
408 lwsl_parser("DROP PING since one pending\n");
412 /* control packets can only be < 128 bytes long */
413 if (wsi->u.ws.rx_ubuf_head > 128 - 3) {
414 lwsl_parser("DROP PING payload too large\n");
418 /* stash the pong payload */
419 memcpy(wsi->u.ws.ping_payload_buf + LWS_PRE,
420 &wsi->u.ws.rx_ubuf[LWS_PRE],
421 wsi->u.ws.rx_ubuf_head);
423 wsi->u.ws.ping_payload_len = wsi->u.ws.rx_ubuf_head;
424 wsi->u.ws.ping_pending_flag = 1;
426 /* get it sent as soon as possible */
427 lws_callback_on_writable(wsi);
429 wsi->u.ws.rx_ubuf_head = 0;
434 lwsl_info("client receied pong\n");
435 lwsl_hexdump(&wsi->u.ws.rx_ubuf[LWS_PRE],
436 wsi->u.ws.rx_ubuf_head);
439 callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
442 case LWSWSOPC_CONTINUATION:
443 case LWSWSOPC_TEXT_FRAME:
444 case LWSWSOPC_BINARY_FRAME:
449 lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
452 * It's something special we can't understand here.
453 * Pass the payload up to the extension's parsing
457 eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
458 eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
460 if (lws_ext_cb_active(wsi,
461 LWS_EXT_CB_EXTENDED_PAYLOAD_RX,
462 &eff_buf, 0) <= 0) { /* not handle or fail */
464 lwsl_ext("Unhandled ext opc 0x%x\n", wsi->u.ws.opcode);
465 wsi->u.ws.rx_ubuf_head = 0;
474 * No it's real payload, pass it up to the user callback.
475 * It's nicely buffered with the pre-padding taken care of
476 * so it can be sent straight out again using lws_write
481 eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
482 eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
485 n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0);
486 lwsl_ext("Ext RX returned %d\n", n);
487 if (n < 0) /* fail */
490 lwsl_ext("post inflate eff_buf len %d\n", eff_buf.token_len);
492 if (rx_draining_ext && !eff_buf.token_len) {
493 lwsl_err(" --- ignoring zero drain result, ending drain\n");
497 if (wsi->u.ws.check_utf8 && !wsi->u.ws.defeat_check_utf8) {
498 if (lws_check_utf8(&wsi->u.ws.utf8,
499 (unsigned char *)eff_buf.token,
503 /* we are ending partway through utf-8 character? */
504 if (!wsi->u.ws.rx_packet_length && wsi->u.ws.final && wsi->u.ws.utf8 && !n) {
505 lwsl_info("FINAL utf8 error\n");
506 utf8_fail: lwsl_info("utf8 error\n");
511 if (eff_buf.token_len < 0 &&
512 callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
518 eff_buf.token[eff_buf.token_len] = '\0';
520 if (!wsi->protocol->callback)
523 if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
524 lwsl_info("Client doing pong callback\n");
526 if (n && eff_buf.token_len) {
527 /* extension had more... main loop will come back
528 * we want callback to be done with this set, if so,
529 * because lws_is_final() hides it was final until the
532 wsi->u.ws.rx_draining_ext = 1;
533 wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list;
534 pt->rx_draining_ext_list = wsi;
535 lwsl_ext("%s: RX EXT DRAINING: Adding to list\n", __func__);
537 if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
538 wsi->state == LWSS_AWAITING_CLOSE_ACK)
541 m = wsi->protocol->callback(wsi,
542 (enum lws_callback_reasons)callback_action,
543 wsi->user_space, eff_buf.token, eff_buf.token_len);
545 /* if user code wants to close, let caller know */
550 wsi->u.ws.rx_ubuf_head = 0;
553 lwsl_err("client rx illegal state\n");
560 lwsl_warn("Control frame asking for extended length is illegal\n");
561 /* kill the connection */