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 int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
27 struct lws_tokens eff_buf;
30 switch (wsi->lws_rx_parse_state) {
33 switch (wsi->ietf_spec_revision) {
36 wsi->u.ws.opcode = c & 0xf;
37 wsi->u.ws.rsv = (c & 0x70);
38 wsi->u.ws.final = !!((c >> 7) & 1);
39 switch (wsi->u.ws.opcode) {
40 case LWSWSOPC_TEXT_FRAME:
41 case LWSWSOPC_BINARY_FRAME:
42 wsi->u.ws.frame_is_binary = wsi->u.ws.opcode ==
43 LWSWSOPC_BINARY_FRAME;
46 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
50 lwsl_err("unknown spec version %02d\n",
51 wsi->ietf_spec_revision);
56 case LWS_RXPS_04_FRAME_HDR_LEN:
58 wsi->u.ws.this_frame_masked = !!(c & 0x80);
62 /* control frames are not allowed to have big lengths */
63 if (wsi->u.ws.opcode & 8)
64 goto illegal_ctl_length;
65 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
68 /* control frames are not allowed to have big lengths */
69 if (wsi->u.ws.opcode & 8)
70 goto illegal_ctl_length;
71 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
74 wsi->u.ws.rx_packet_length = c;
75 if (wsi->u.ws.this_frame_masked)
76 wsi->lws_rx_parse_state =
77 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
80 wsi->lws_rx_parse_state =
81 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
83 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
91 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
92 wsi->u.ws.rx_packet_length = c << 8;
93 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
96 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
97 wsi->u.ws.rx_packet_length |= c;
98 if (wsi->u.ws.this_frame_masked)
99 wsi->lws_rx_parse_state =
100 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
102 if (wsi->u.ws.rx_packet_length)
103 wsi->lws_rx_parse_state =
104 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
106 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
112 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
114 lwsl_warn("b63 of length must be zero\n");
115 /* kill the connection */
119 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
121 wsi->u.ws.rx_packet_length = 0;
123 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
126 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
128 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
130 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
133 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
135 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
137 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
140 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
142 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
144 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
147 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
148 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
149 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
152 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
153 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
154 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
157 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
158 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
159 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
162 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
163 wsi->u.ws.rx_packet_length |= (size_t)c;
164 if (wsi->u.ws.this_frame_masked)
165 wsi->lws_rx_parse_state =
166 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
168 if (wsi->u.ws.rx_packet_length)
169 wsi->lws_rx_parse_state =
170 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
172 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
178 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
179 wsi->u.ws.mask_nonce[0] = c;
181 wsi->u.ws.all_zero_nonce = 0;
182 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
185 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
186 wsi->u.ws.mask_nonce[1] = c;
188 wsi->u.ws.all_zero_nonce = 0;
189 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
192 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
193 wsi->u.ws.mask_nonce[2] = c;
195 wsi->u.ws.all_zero_nonce = 0;
196 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
199 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
200 wsi->u.ws.mask_nonce[3] = c;
202 wsi->u.ws.all_zero_nonce = 0;
204 if (wsi->u.ws.rx_packet_length)
205 wsi->lws_rx_parse_state =
206 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
208 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
213 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
215 if (!wsi->u.ws.rx_user_buffer) {
216 lwsl_err("NULL client rx_user_buffer\n");
220 if ((!wsi->u.ws.this_frame_masked) || wsi->u.ws.all_zero_nonce)
221 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
222 (wsi->u.ws.rx_user_buffer_head++)] = c;
224 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
225 (wsi->u.ws.rx_user_buffer_head++)] =
226 c ^ wsi->u.ws.mask_nonce[
227 (wsi->u.ws.frame_mask_index++) & 3];
229 if (--wsi->u.ws.rx_packet_length == 0) {
230 /* spill because we have the whole frame */
231 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
236 * if there's no protocol max frame size given, we are
237 * supposed to default to LWS_MAX_SOCKET_IO_BUF
240 if (!wsi->protocol->rx_buffer_size &&
241 wsi->u.ws.rx_user_buffer_head !=
242 LWS_MAX_SOCKET_IO_BUF)
245 if (wsi->protocol->rx_buffer_size &&
246 wsi->u.ws.rx_user_buffer_head !=
247 wsi->protocol->rx_buffer_size)
250 /* spill because we filled our rx buffer */
256 * is this frame a control packet we should take care of at this
257 * layer? If so service it and hide it from the user callback
260 switch (wsi->u.ws.opcode) {
262 /* is this an acknowledgement of our close? */
263 if (wsi->state == LWSS_AWAITING_CLOSE_ACK) {
265 * fine he has told us he is closing too, let's
268 lwsl_parser("seen server's close ack\n");
271 lwsl_parser("client sees server close len = %d\n",
272 wsi->u.ws.rx_user_buffer_head);
274 * parrot the close packet payload back
275 * we do not care about how it went, we are closing
276 * immediately afterwards
278 lws_write(wsi, (unsigned char *)
279 &wsi->u.ws.rx_user_buffer[
280 LWS_SEND_BUFFER_PRE_PADDING],
281 wsi->u.ws.rx_user_buffer_head, LWS_WRITE_CLOSE);
282 wsi->state = LWSS_RETURNED_CLOSE_ALREADY;
283 /* close the connection */
287 lwsl_info("received %d byte ping, sending pong\n",
288 wsi->u.ws.rx_user_buffer_head);
290 if (wsi->u.ws.ping_pending_flag) {
292 * there is already a pending ping payload
293 * we should just log and drop
295 lwsl_parser("DROP PING since one pending\n");
299 /* control packets can only be < 128 bytes long */
300 if (wsi->u.ws.rx_user_buffer_head > 128 - 4) {
301 lwsl_parser("DROP PING payload too large\n");
305 /* if existing buffer is too small, drop it */
306 if (wsi->u.ws.ping_payload_buf &&
307 wsi->u.ws.ping_payload_alloc <
308 wsi->u.ws.rx_user_buffer_head)
309 lws_free_set_NULL(wsi->u.ws.ping_payload_buf);
311 /* if no buffer, allocate it */
312 if (!wsi->u.ws.ping_payload_buf) {
313 wsi->u.ws.ping_payload_buf =
314 lws_malloc(wsi->u.ws.rx_user_buffer_head +
315 LWS_SEND_BUFFER_PRE_PADDING);
316 wsi->u.ws.ping_payload_alloc =
317 wsi->u.ws.rx_user_buffer_head;
320 /* stash the pong payload */
321 memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING,
322 &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
323 wsi->u.ws.rx_user_buffer_head);
325 wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head;
326 wsi->u.ws.ping_pending_flag = 1;
328 /* get it sent as soon as possible */
329 lws_callback_on_writable(wsi);
331 wsi->u.ws.rx_user_buffer_head = 0;
336 lwsl_info("client receied pong\n");
337 lwsl_hexdump(&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
338 wsi->u.ws.rx_user_buffer_head);
341 callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
344 case LWSWSOPC_CONTINUATION:
345 case LWSWSOPC_TEXT_FRAME:
346 case LWSWSOPC_BINARY_FRAME:
351 lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
354 * It's something special we can't understand here.
355 * Pass the payload up to the extension's parsing
359 eff_buf.token = &wsi->u.ws.rx_user_buffer[
360 LWS_SEND_BUFFER_PRE_PADDING];
361 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
363 if (lws_ext_cb_wsi_active_exts(wsi,
364 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
365 &eff_buf, 0) <= 0) { /* not handle or fail */
367 lwsl_ext("Unhandled ext opc 0x%x\n",
369 wsi->u.ws.rx_user_buffer_head = 0;
378 * No it's real payload, pass it up to the user callback.
379 * It's nicely buffered with the pre-padding taken care of
380 * so it can be sent straight out again using lws_write
385 eff_buf.token = &wsi->u.ws.rx_user_buffer[
386 LWS_SEND_BUFFER_PRE_PADDING];
387 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
389 if (lws_ext_cb_wsi_active_exts(wsi,
390 LWS_EXT_CALLBACK_PAYLOAD_RX,
391 &eff_buf, 0) < 0) /* fail */
394 if (eff_buf.token_len <= 0 &&
395 callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
398 eff_buf.token[eff_buf.token_len] = '\0';
400 if (!wsi->protocol->callback)
403 if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
404 lwsl_info("Client doing pong callback\n");
406 m = wsi->protocol->callback(wsi,
407 (enum lws_callback_reasons)callback_action,
408 wsi->user_space, eff_buf.token, eff_buf.token_len);
410 /* if user code wants to close, let caller know */
415 wsi->u.ws.rx_user_buffer_head = 0;
418 lwsl_err("client rx illegal state\n");
426 lwsl_warn("Control frame asking for extended length is illegal\n");
427 /* kill the connection */