2 * libwebsockets - small server side websockets and web server implementation
4 * Copyright (C) 2010-2013 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 libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
26 int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
28 struct lws_tokens eff_buf;
29 #ifndef LWS_NO_EXTENSIONS
34 switch (wsi->lws_rx_parse_state) {
37 switch (wsi->ietf_spec_revision) {
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;
50 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
54 lwsl_err("unknown spec version %02d\n",
55 wsi->ietf_spec_revision);
61 case LWS_RXPS_04_FRAME_HDR_LEN:
63 wsi->u.ws.this_frame_masked = !!(c & 0x80);
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;
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;
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;
85 wsi->lws_rx_parse_state =
86 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
88 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
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;
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;
107 if (wsi->u.ws.rx_packet_length)
108 wsi->lws_rx_parse_state =
109 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
111 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
117 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
119 lwsl_warn("b63 of length must be zero\n");
120 /* kill the connection */
124 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
126 wsi->u.ws.rx_packet_length = 0;
128 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
131 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
133 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
135 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
138 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
140 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
142 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
145 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
147 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
149 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
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;
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;
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;
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;
173 if (wsi->u.ws.rx_packet_length)
174 wsi->lws_rx_parse_state =
175 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
177 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
183 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
184 wsi->u.ws.frame_masking_nonce_04[0] = c;
186 wsi->u.ws.all_zero_nonce = 0;
187 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
190 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
191 wsi->u.ws.frame_masking_nonce_04[1] = c;
193 wsi->u.ws.all_zero_nonce = 0;
194 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
197 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
198 wsi->u.ws.frame_masking_nonce_04[2] = c;
200 wsi->u.ws.all_zero_nonce = 0;
201 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
204 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
205 wsi->u.ws.frame_masking_nonce_04[3] = c;
207 wsi->u.ws.all_zero_nonce = 0;
209 if (wsi->u.ws.rx_packet_length)
210 wsi->lws_rx_parse_state =
211 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
213 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
218 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
220 if (!wsi->u.ws.rx_user_buffer)
221 lwsl_err("NULL client rx_user_buffer\n");
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;
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];
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;
239 * if there's no protocol max frame size given, we are
240 * supposed to default to LWS_MAX_SOCKET_IO_BUF
243 if (!wsi->protocol->rx_buffer_size &&
244 wsi->u.ws.rx_user_buffer_head !=
245 LWS_MAX_SOCKET_IO_BUF)
248 if (wsi->protocol->rx_buffer_size &&
249 wsi->u.ws.rx_user_buffer_head !=
250 wsi->protocol->rx_buffer_size)
253 /* spill because we filled our rx buffer */
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
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) {
268 * fine he has told us he is closing too, let's
271 lwsl_parser("seen server's close ack\n");
274 lwsl_parser("client sees server close len = %d\n",
275 wsi->u.ws.rx_user_buffer_head);
277 * parrot the close packet payload back
278 * we do not care about how it went, we are closing
279 * immediately afterwards
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 */
289 case LWS_WS_OPCODE_07__PING:
290 lwsl_info("client received ping, doing pong\n");
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
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,
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);
311 callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
314 case LWS_WS_OPCODE_07__CONTINUATION:
315 case LWS_WS_OPCODE_07__TEXT_FRAME:
316 case LWS_WS_OPCODE_07__BINARY_FRAME:
321 lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
322 #ifndef LWS_NO_EXTENSIONS
324 * It's something special we can't understand here.
325 * Pass the payload up to the extension's parsing
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;
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],
348 lwsl_ext("Unhandled ext opc 0x%x\n",
350 wsi->u.ws.rx_user_buffer_head = 0;
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
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],
379 "Ext '%s' failed to handle payload!\n",
380 wsi->active_extensions[n]->name);
385 if (eff_buf.token_len <= 0)
388 eff_buf.token[eff_buf.token_len] = '\0';
390 if (!wsi->protocol->callback)
393 if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
394 lwsl_info("Client doing pong callback\n");
396 wsi->protocol->callback(
397 wsi->protocol->owning_server,
399 (enum libwebsocket_callback_reasons)callback_action,
405 wsi->u.ws.rx_user_buffer_head = 0;
408 lwsl_err("client rx illegal state\n");
416 lwsl_warn("Control frame asking for extended length is illegal\n");
417 /* kill the connection */