blob: e548b4f0e48dbd3881d5c54c171e1d769c3e339c [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
Andy Green76f61e72013-01-16 11:53:05 +080024int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
25{
Andy Green76f61e72013-01-16 11:53:05 +080026 int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
27 int handled;
28 struct lws_tokens eff_buf;
Andy Green3182ece2013-01-20 17:08:31 +080029#ifndef LWS_NO_EXTENSIONS
Andy Green760c3d42013-02-18 10:43:18 +080030 int n;
Andy Green76f61e72013-01-16 11:53:05 +080031 int m;
Andy Green3182ece2013-01-20 17:08:31 +080032#endif
Andy Green76f61e72013-01-16 11:53:05 +080033
Andy Green76f61e72013-01-16 11:53:05 +080034 switch (wsi->lws_rx_parse_state) {
35 case LWS_RXPS_NEW:
36
37 switch (wsi->ietf_spec_revision) {
Andy Green5738c0e2013-01-21 09:53:35 +080038
Andy Green76f61e72013-01-16 11:53:05 +080039 case 13:
Andy Green623a98d2013-01-21 11:04:23 +080040 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) {
Andy Green10601c12013-01-19 10:39:35 +080044 case LWS_WS_OPCODE_07__TEXT_FRAME:
Andy Green10601c12013-01-19 10:39:35 +080045 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Greenb5b23192013-02-11 17:13:32 +080046 wsi->u.ws.frame_is_binary = wsi->u.ws.opcode ==
47 LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +080048 break;
49 }
Andy Green76f61e72013-01-16 11:53:05 +080050 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
51 break;
52
53 default:
Andy Greenb5b23192013-02-11 17:13:32 +080054 lwsl_err("unknown spec version %02d\n",
Andy Green76f61e72013-01-16 11:53:05 +080055 wsi->ietf_spec_revision);
56 break;
57 }
58 break;
59
60
61 case LWS_RXPS_04_FRAME_HDR_LEN:
62
Andy Green623a98d2013-01-21 11:04:23 +080063 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green76f61e72013-01-16 11:53:05 +080064
65 switch (c & 0x7f) {
66 case 126:
67 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +080068 if (wsi->u.ws.opcode & 8)
Andy Green76f61e72013-01-16 11:53:05 +080069 goto illegal_ctl_length;
70 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
71 break;
72 case 127:
73 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +080074 if (wsi->u.ws.opcode & 8)
Andy Green76f61e72013-01-16 11:53:05 +080075 goto illegal_ctl_length;
76 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
77 break;
78 default:
Andy Green623a98d2013-01-21 11:04:23 +080079 wsi->u.ws.rx_packet_length = c;
80 if (wsi->u.ws.this_frame_masked)
Andy Green76f61e72013-01-16 11:53:05 +080081 wsi->lws_rx_parse_state =
82 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
83 else {
84 if (c)
85 wsi->lws_rx_parse_state =
86 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
87 else {
88 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
89 goto spill;
90 }
91 }
92 break;
93 }
94 break;
95
96 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +080097 wsi->u.ws.rx_packet_length = c << 8;
Andy Green76f61e72013-01-16 11:53:05 +080098 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
99 break;
100
101 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800102 wsi->u.ws.rx_packet_length |= c;
103 if (wsi->u.ws.this_frame_masked)
Andy Green76f61e72013-01-16 11:53:05 +0800104 wsi->lws_rx_parse_state =
105 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
106 else {
Andy Green623a98d2013-01-21 11:04:23 +0800107 if (wsi->u.ws.rx_packet_length)
Andy Green76f61e72013-01-16 11:53:05 +0800108 wsi->lws_rx_parse_state =
109 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
110 else {
111 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
112 goto spill;
113 }
114 }
115 break;
116
117 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
118 if (c & 0x80) {
119 lwsl_warn("b63 of length must be zero\n");
120 /* kill the connection */
121 return -1;
122 }
123#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800124 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
Andy Green76f61e72013-01-16 11:53:05 +0800125#else
Andy Green623a98d2013-01-21 11:04:23 +0800126 wsi->u.ws.rx_packet_length = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800127#endif
128 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
129 break;
130
131 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
132#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800133 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Green76f61e72013-01-16 11:53:05 +0800134#endif
135 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
136 break;
137
138 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
139#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800140 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
Andy Green76f61e72013-01-16 11:53:05 +0800141#endif
142 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
143 break;
144
145 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
146#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800147 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
Andy Green76f61e72013-01-16 11:53:05 +0800148#endif
149 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
150 break;
151
152 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800153 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green76f61e72013-01-16 11:53:05 +0800154 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
155 break;
156
157 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800158 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green76f61e72013-01-16 11:53:05 +0800159 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
160 break;
161
162 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800163 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green76f61e72013-01-16 11:53:05 +0800164 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
165 break;
166
167 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800168 wsi->u.ws.rx_packet_length |= (size_t)c;
169 if (wsi->u.ws.this_frame_masked)
Andy Green76f61e72013-01-16 11:53:05 +0800170 wsi->lws_rx_parse_state =
171 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
172 else {
Andy Green623a98d2013-01-21 11:04:23 +0800173 if (wsi->u.ws.rx_packet_length)
Andy Green76f61e72013-01-16 11:53:05 +0800174 wsi->lws_rx_parse_state =
175 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
176 else {
177 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
178 goto spill;
179 }
180 }
181 break;
182
183 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green623a98d2013-01-21 11:04:23 +0800184 wsi->u.ws.frame_masking_nonce_04[0] = c;
Andy Green76f61e72013-01-16 11:53:05 +0800185 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800186 wsi->u.ws.all_zero_nonce = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800187 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
188 break;
189
190 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green623a98d2013-01-21 11:04:23 +0800191 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green76f61e72013-01-16 11:53:05 +0800192 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800193 wsi->u.ws.all_zero_nonce = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800194 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
195 break;
196
197 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green623a98d2013-01-21 11:04:23 +0800198 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green76f61e72013-01-16 11:53:05 +0800199 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800200 wsi->u.ws.all_zero_nonce = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800201 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
202 break;
203
204 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green623a98d2013-01-21 11:04:23 +0800205 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green76f61e72013-01-16 11:53:05 +0800206 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800207 wsi->u.ws.all_zero_nonce = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800208
Andy Green623a98d2013-01-21 11:04:23 +0800209 if (wsi->u.ws.rx_packet_length)
Andy Green76f61e72013-01-16 11:53:05 +0800210 wsi->lws_rx_parse_state =
211 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
212 else {
213 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
214 goto spill;
215 }
216 break;
217
Andy Green76f61e72013-01-16 11:53:05 +0800218 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green54495112013-02-06 21:10:16 +0900219
220 if (!wsi->u.ws.rx_user_buffer)
221 lwsl_err("NULL client rx_user_buffer\n");
222
Andy Green623a98d2013-01-21 11:04:23 +0800223 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;
Andy Green76f61e72013-01-16 11:53:05 +0800226 else
Andy Green623a98d2013-01-21 11:04:23 +0800227 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
228 (wsi->u.ws.rx_user_buffer_head++)] =
Andy Greenb5b23192013-02-11 17:13:32 +0800229 c ^ wsi->u.ws.frame_masking_nonce_04[
230 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green76f61e72013-01-16 11:53:05 +0800231
Andy Green623a98d2013-01-21 11:04:23 +0800232 if (--wsi->u.ws.rx_packet_length == 0) {
Andy Greenff5dbf92013-02-14 10:18:31 +0800233 /* spill because we have the whole frame */
Andy Green76f61e72013-01-16 11:53:05 +0800234 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
235 goto spill;
236 }
Andy Greenff5dbf92013-02-14 10:18:31 +0800237
238 /*
239 * if there's no protocol max frame size given, we are
240 * supposed to default to LWS_MAX_SOCKET_IO_BUF
241 */
242
243 if (!wsi->protocol->rx_buffer_size &&
244 wsi->u.ws.rx_user_buffer_head !=
245 LWS_MAX_SOCKET_IO_BUF)
Andy Green76f61e72013-01-16 11:53:05 +0800246 break;
Andy Greenff5dbf92013-02-14 10:18:31 +0800247 else
248 if (wsi->protocol->rx_buffer_size &&
249 wsi->u.ws.rx_user_buffer_head !=
250 wsi->protocol->rx_buffer_size)
251 break;
252
253 /* spill because we filled our rx buffer */
Andy Green76f61e72013-01-16 11:53:05 +0800254spill:
255
256 handled = 0;
257
258 /*
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
261 */
262
Andy Green623a98d2013-01-21 11:04:23 +0800263 switch (wsi->u.ws.opcode) {
Andy Green76f61e72013-01-16 11:53:05 +0800264 case LWS_WS_OPCODE_07__CLOSE:
265 /* is this an acknowledgement of our close? */
266 if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
267 /*
268 * fine he has told us he is closing too, let's
269 * finish our close
270 */
271 lwsl_parser("seen server's close ack\n");
272 return -1;
273 }
Andy Greenb5b23192013-02-11 17:13:32 +0800274 lwsl_parser("client sees server close len = %d\n",
275 wsi->u.ws.rx_user_buffer_head);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800276 /*
277 * parrot the close packet payload back
278 * we do not care about how it went, we are closing
279 * immediately afterwards
280 */
Andy Green760c3d42013-02-18 10:43:18 +0800281 libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800282 &wsi->u.ws.rx_user_buffer[
283 LWS_SEND_BUFFER_PRE_PADDING],
284 wsi->u.ws.rx_user_buffer_head, LWS_WRITE_CLOSE);
Andy Green76f61e72013-01-16 11:53:05 +0800285 wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
286 /* close the connection */
287 return -1;
288
289 case LWS_WS_OPCODE_07__PING:
Andy Greenf7248f82013-01-16 14:35:12 +0800290 lwsl_info("client received ping, doing pong\n");
Andy Greenfc7c5e42013-02-23 10:50:10 +0800291 /*
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
295 */
Andy Green760c3d42013-02-18 10:43:18 +0800296 libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800297 &wsi->u.ws.rx_user_buffer[
298 LWS_SEND_BUFFER_PRE_PADDING],
299 wsi->u.ws.rx_user_buffer_head,
300 LWS_WRITE_PONG);
Andy Green76f61e72013-01-16 11:53:05 +0800301 handled = 1;
302 break;
303
304 case LWS_WS_OPCODE_07__PONG:
Andy Greenf7248f82013-01-16 14:35:12 +0800305 lwsl_info("client receied pong\n");
Andy Greenb5b23192013-02-11 17:13:32 +0800306 lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
307 LWS_SEND_BUFFER_PRE_PADDING],
Andy Green623a98d2013-01-21 11:04:23 +0800308 wsi->u.ws.rx_user_buffer_head);
Andy Green76f61e72013-01-16 11:53:05 +0800309
310 /* issue it */
311 callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
312 break;
313
314 case LWS_WS_OPCODE_07__CONTINUATION:
315 case LWS_WS_OPCODE_07__TEXT_FRAME:
316 case LWS_WS_OPCODE_07__BINARY_FRAME:
317 break;
318
319 default:
320
Andy Greenb5b23192013-02-11 17:13:32 +0800321 lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
Andy Green3182ece2013-01-20 17:08:31 +0800322#ifndef LWS_NO_EXTENSIONS
Andy Green76f61e72013-01-16 11:53:05 +0800323 /*
324 * It's something special we can't understand here.
325 * Pass the payload up to the extension's parsing
326 * state machine.
327 */
328
Andy Green623a98d2013-01-21 11:04:23 +0800329 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Green76f61e72013-01-16 11:53:05 +0800330 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800331 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green76f61e72013-01-16 11:53:05 +0800332
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],
339 &eff_buf, 0);
340 if (m)
341 handled = 1;
342 }
343
344 if (!handled) {
Andy Green3182ece2013-01-20 17:08:31 +0800345#else
346 {
347#endif
Andy Greenb5b23192013-02-11 17:13:32 +0800348 lwsl_ext("Unhandled ext opc 0x%x\n",
349 wsi->u.ws.opcode);
Andy Green623a98d2013-01-21 11:04:23 +0800350 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800351
352 return 0;
353 }
354
355 break;
356 }
357
358 /*
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
362 */
363 if (handled)
364 goto already_done;
365
Andy Green623a98d2013-01-21 11:04:23 +0800366 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Green76f61e72013-01-16 11:53:05 +0800367 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800368 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green3182ece2013-01-20 17:08:31 +0800369#ifndef LWS_NO_EXTENSIONS
Andy Green76f61e72013-01-16 11:53:05 +0800370 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],
376 &eff_buf, 0);
377 if (m < 0) {
378 lwsl_ext(
Andy Greenb5b23192013-02-11 17:13:32 +0800379 "Ext '%s' failed to handle payload!\n",
380 wsi->active_extensions[n]->name);
Andy Green76f61e72013-01-16 11:53:05 +0800381 return -1;
382 }
383 }
Andy Green3182ece2013-01-20 17:08:31 +0800384#endif
Andy Greenb5b23192013-02-11 17:13:32 +0800385 if (eff_buf.token_len <= 0)
386 goto already_done;
Andy Green76f61e72013-01-16 11:53:05 +0800387
Andy Greenb5b23192013-02-11 17:13:32 +0800388 eff_buf.token[eff_buf.token_len] = '\0';
389
390 if (!wsi->protocol->callback)
391 goto already_done;
392
393 if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
394 lwsl_info("Client doing pong callback\n");
395
396 wsi->protocol->callback(
397 wsi->protocol->owning_server,
398 wsi,
Andy Green76f61e72013-01-16 11:53:05 +0800399 (enum libwebsocket_callback_reasons)callback_action,
Andy Greenb5b23192013-02-11 17:13:32 +0800400 wsi->user_space,
401 eff_buf.token,
402 eff_buf.token_len);
403
Andy Green76f61e72013-01-16 11:53:05 +0800404already_done:
Andy Green623a98d2013-01-21 11:04:23 +0800405 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green76f61e72013-01-16 11:53:05 +0800406 break;
407 default:
408 lwsl_err("client rx illegal state\n");
409 return 1;
410 }
411
412 return 0;
413
414illegal_ctl_length:
415
Andy Greenb5b23192013-02-11 17:13:32 +0800416 lwsl_warn("Control frame asking for extended length is illegal\n");
Andy Green76f61e72013-01-16 11:53:05 +0800417 /* kill the connection */
418 return -1;
419
420}
421
422