1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

refactor migrate client stuff to client.c

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2013-01-16 11:53:05 +08:00
parent 53f437e4e1
commit 76f61e7ade
5 changed files with 1538 additions and 1450 deletions

View file

@ -3,6 +3,8 @@ include_HEADERS=libwebsockets.h
dist_libwebsockets_la_SOURCES=libwebsockets.c \
handshake.c \
parsers.c \
client.c \
client-parser.c \
libwebsockets.h \
base64-decode.c \
client-handshake.c \

517
lib/client-parser.c Normal file
View file

@ -0,0 +1,517 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
#ifdef WIN32
#include <io.h>
#endif
int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
{
int n;
unsigned char buf[20 + 4];
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
int handled;
struct lws_tokens eff_buf;
int m;
lwsl_parser(" CRX: %02X %d\n", c, wsi->lws_rx_parse_state);
switch (wsi->lws_rx_parse_state) {
case LWS_RXPS_NEW:
switch (wsi->ietf_spec_revision) {
/* Firefox 4.0b6 likes this as of 30 Oct */
case 0:
if (c == 0xff)
wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
if (c == 0) {
wsi->lws_rx_parse_state =
LWS_RXPS_EAT_UNTIL_76_FF;
wsi->rx_user_buffer_head = 0;
}
break;
case 4:
case 5:
case 6:
case 7:
case 8:
case 13:
/*
* 04 logical framing from the spec (all this is masked when
* incoming and has to be unmasked)
*
* We ignore the possibility of extension data because we don't
* negotiate any extensions at the moment.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-------+-+-------------+-------------------------------+
* |F|R|R|R| opcode|R| Payload len | Extended payload length |
* |I|S|S|S| (4) |S| (7) | (16/63) |
* |N|V|V|V| |V| | (if payload len==126/127) |
* | |1|2|3| |4| | |
* +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
* | Extended payload length continued, if payload len == 127 |
* + - - - - - - - - - - - - - - - +-------------------------------+
* | | Extension data |
* +-------------------------------+ - - - - - - - - - - - - - - - +
* : :
* +---------------------------------------------------------------+
* : Application data :
* +---------------------------------------------------------------+
*
* We pass payload through to userland as soon as we get it, ignoring
* FIN. It's up to userland to buffer it up if it wants to see a
* whole unfragmented block of the original size (which may be up to
* 2^63 long!)
*
* Notice in v7 RSV4 is set to indicate 32-bit frame key is coming in
* after length, unlike extension data which is now deprecated, this
* does not impact the payload length calculation.
*/
/*
* 04 spec defines the opcode like this: (1, 2, and 3 are
* "control frame" opcodes which may not be fragmented or
* have size larger than 126)
*
* frame-opcode =
* %x0 ; continuation frame
* / %x1 ; connection close
* / %x2 ; ping
* / %x3 ; pong
* / %x4 ; text frame
* / %x5 ; binary frame
* / %x6-F ; reserved
*
* FIN (b7)
*/
if (wsi->ietf_spec_revision < 7)
switch (c & 0xf) {
case LWS_WS_OPCODE_04__CONTINUATION:
wsi->opcode =
LWS_WS_OPCODE_07__CONTINUATION;
break;
case LWS_WS_OPCODE_04__CLOSE:
wsi->opcode = LWS_WS_OPCODE_07__CLOSE;
break;
case LWS_WS_OPCODE_04__PING:
wsi->opcode = LWS_WS_OPCODE_07__PING;
break;
case LWS_WS_OPCODE_04__PONG:
wsi->opcode = LWS_WS_OPCODE_07__PONG;
break;
case LWS_WS_OPCODE_04__TEXT_FRAME:
wsi->opcode =
LWS_WS_OPCODE_07__TEXT_FRAME;
break;
case LWS_WS_OPCODE_04__BINARY_FRAME:
wsi->opcode =
LWS_WS_OPCODE_07__BINARY_FRAME;
break;
default:
lwsl_warn("reserved opcodes not "
"usable pre v7 protocol\n");
return -1;
}
else
wsi->opcode = c & 0xf;
wsi->rsv = (c & 0x70);
wsi->final = !!((c >> 7) & 1);
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
break;
default:
lwsl_err("client_rx_sm doesn't know how "
"to handle spec version %02d\n",
wsi->ietf_spec_revision);
break;
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN:
if ((c & 0x80) && wsi->ietf_spec_revision < 7) {
lwsl_warn("Frame has extensions set illegally 4\n");
/* kill the connection */
return -1;
}
wsi->this_frame_masked = !!(c & 0x80);
switch (c & 0x7f) {
case 126:
/* control frames are not allowed to have big lengths */
if (wsi->opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
break;
case 127:
/* control frames are not allowed to have big lengths */
if (wsi->opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
break;
default:
wsi->rx_packet_length = c;
if (wsi->this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (c)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
wsi->rx_packet_length = c << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_1:
wsi->rx_packet_length |= c;
if (wsi->this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (wsi->rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
if (c & 0x80) {
lwsl_warn("b63 of length must be zero\n");
/* kill the connection */
return -1;
}
#if defined __LP64__
wsi->rx_packet_length = ((size_t)c) << 56;
#else
wsi->rx_packet_length = 0;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_7:
#if defined __LP64__
wsi->rx_packet_length |= ((size_t)c) << 48;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_6:
#if defined __LP64__
wsi->rx_packet_length |= ((size_t)c) << 40;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_5:
#if defined __LP64__
wsi->rx_packet_length |= ((size_t)c) << 32;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
wsi->rx_packet_length |= ((size_t)c) << 24;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_3:
wsi->rx_packet_length |= ((size_t)c) << 16;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_2:
wsi->rx_packet_length |= ((size_t)c) << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_1:
wsi->rx_packet_length |= (size_t)c;
if (wsi->this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (wsi->rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
wsi->frame_masking_nonce_04[0] = c;
if (c)
wsi->all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
wsi->frame_masking_nonce_04[1] = c;
if (c)
wsi->all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
wsi->frame_masking_nonce_04[2] = c;
if (c)
wsi->all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
wsi->frame_masking_nonce_04[3] = c;
if (c)
wsi->all_zero_nonce = 0;
if (wsi->rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
break;
case LWS_RXPS_EAT_UNTIL_76_FF:
if (c == 0xff) {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto issue;
}
wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->rx_user_buffer_head++)] = c;
if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
break;
issue:
if (wsi->protocol->callback)
wsi->protocol->callback(wsi->protocol->owning_server,
wsi,
LWS_CALLBACK_CLIENT_RECEIVE,
wsi->user_space,
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head);
wsi->rx_user_buffer_head = 0;
break;
case LWS_RXPS_SEEN_76_FF:
if (c)
break;
lwsl_parser("Seen that client is requesting "
"a v76 close, sending ack\n");
buf[0] = 0xff;
buf[1] = 0;
n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP);
if (n < 0) {
lwsl_warn("LWS_RXPS_SEEN_76_FF: ERROR writing to socket\n");
return -1;
}
lwsl_parser(" v76 close ack sent, server closing skt\n");
/* returning < 0 will get it closed in parent */
return -1;
case LWS_RXPS_PULLING_76_LENGTH:
break;
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
if ((!wsi->this_frame_masked) || wsi->all_zero_nonce)
wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->rx_user_buffer_head++)] = c;
else
wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->rx_user_buffer_head++)] =
wsi->xor_mask(wsi, c);
if (--wsi->rx_packet_length == 0) {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
break;
spill:
handled = 0;
/*
* is this frame a control packet we should take care of at this
* layer? If so service it and hide it from the user callback
*/
switch (wsi->opcode) {
case LWS_WS_OPCODE_07__CLOSE:
/* is this an acknowledgement of our close? */
if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
/*
* fine he has told us he is closing too, let's
* finish our close
*/
lwsl_parser("seen server's close ack\n");
return -1;
}
lwsl_parser("client sees server close packet len = %d\n", wsi->rx_user_buffer_head);
/* parrot the close packet payload back */
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head, LWS_WRITE_CLOSE);
lwsl_parser("client writing close ack returned %d\n", n);
wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
/* close the connection */
return -1;
case LWS_WS_OPCODE_07__PING:
/* parrot the ping packet payload back as a pong*/
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head, LWS_WRITE_PONG);
handled = 1;
break;
case LWS_WS_OPCODE_07__PONG:
/* keep the statistics... */
wsi->pings_vs_pongs--;
/* issue it */
callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
break;
case LWS_WS_OPCODE_07__CONTINUATION:
case LWS_WS_OPCODE_07__TEXT_FRAME:
case LWS_WS_OPCODE_07__BINARY_FRAME:
break;
default:
lwsl_parser("Reserved opcode 0x%2X\n", wsi->opcode);
/*
* It's something special we can't understand here.
* Pass the payload up to the extension's parsing
* state machine.
*/
eff_buf.token = &wsi->rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->rx_user_buffer_head;
for (n = 0; n < wsi->count_active_extensions; n++) {
m = wsi->active_extensions[n]->callback(
wsi->protocol->owning_server,
wsi->active_extensions[n], wsi,
LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
wsi->active_extensions_user[n],
&eff_buf, 0);
if (m)
handled = 1;
}
if (!handled) {
lwsl_ext("Unhandled extended opcode "
"0x%x - ignoring frame\n", wsi->opcode);
wsi->rx_user_buffer_head = 0;
return 0;
}
break;
}
/*
* No it's real payload, pass it up to the user callback.
* It's nicely buffered with the pre-padding taken care of
* so it can be sent straight out again using libwebsocket_write
*/
if (handled)
goto already_done;
eff_buf.token = &wsi->rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->rx_user_buffer_head;
for (n = 0; n < wsi->count_active_extensions; n++) {
m = wsi->active_extensions[n]->callback(
wsi->protocol->owning_server,
wsi->active_extensions[n], wsi,
LWS_EXT_CALLBACK_PAYLOAD_RX,
wsi->active_extensions_user[n],
&eff_buf, 0);
if (m < 0) {
lwsl_ext(
"Extension '%s' failed to handle payload!\n",
wsi->active_extensions[n]->name);
return -1;
}
}
if (eff_buf.token_len > 0) {
eff_buf.token[eff_buf.token_len] = '\0';
if (wsi->protocol->callback)
wsi->protocol->callback(
wsi->protocol->owning_server,
wsi,
(enum libwebsocket_callback_reasons)callback_action,
wsi->user_space,
eff_buf.token,
eff_buf.token_len);
}
already_done:
wsi->rx_user_buffer_head = 0;
break;
default:
lwsl_err("client rx illegal state\n");
return 1;
}
return 0;
illegal_ctl_length:
lwsl_warn("Control frame asking for "
"extended length is illegal\n");
/* kill the connection */
return -1;
}

1015
lib/client.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -886,495 +886,6 @@ illegal_ctl_length:
}
int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
{
int n;
unsigned char buf[20 + 4];
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
int handled;
struct lws_tokens eff_buf;
int m;
lwsl_parser(" CRX: %02X %d\n", c, wsi->lws_rx_parse_state);
switch (wsi->lws_rx_parse_state) {
case LWS_RXPS_NEW:
switch (wsi->ietf_spec_revision) {
/* Firefox 4.0b6 likes this as of 30 Oct */
case 0:
if (c == 0xff)
wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
if (c == 0) {
wsi->lws_rx_parse_state =
LWS_RXPS_EAT_UNTIL_76_FF;
wsi->rx_user_buffer_head = 0;
}
break;
case 4:
case 5:
case 6:
case 7:
case 8:
case 13:
/*
* 04 logical framing from the spec (all this is masked when
* incoming and has to be unmasked)
*
* We ignore the possibility of extension data because we don't
* negotiate any extensions at the moment.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-------+-+-------------+-------------------------------+
* |F|R|R|R| opcode|R| Payload len | Extended payload length |
* |I|S|S|S| (4) |S| (7) | (16/63) |
* |N|V|V|V| |V| | (if payload len==126/127) |
* | |1|2|3| |4| | |
* +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
* | Extended payload length continued, if payload len == 127 |
* + - - - - - - - - - - - - - - - +-------------------------------+
* | | Extension data |
* +-------------------------------+ - - - - - - - - - - - - - - - +
* : :
* +---------------------------------------------------------------+
* : Application data :
* +---------------------------------------------------------------+
*
* We pass payload through to userland as soon as we get it, ignoring
* FIN. It's up to userland to buffer it up if it wants to see a
* whole unfragmented block of the original size (which may be up to
* 2^63 long!)
*
* Notice in v7 RSV4 is set to indicate 32-bit frame key is coming in
* after length, unlike extension data which is now deprecated, this
* does not impact the payload length calculation.
*/
/*
* 04 spec defines the opcode like this: (1, 2, and 3 are
* "control frame" opcodes which may not be fragmented or
* have size larger than 126)
*
* frame-opcode =
* %x0 ; continuation frame
* / %x1 ; connection close
* / %x2 ; ping
* / %x3 ; pong
* / %x4 ; text frame
* / %x5 ; binary frame
* / %x6-F ; reserved
*
* FIN (b7)
*/
if (wsi->ietf_spec_revision < 7)
switch (c & 0xf) {
case LWS_WS_OPCODE_04__CONTINUATION:
wsi->opcode =
LWS_WS_OPCODE_07__CONTINUATION;
break;
case LWS_WS_OPCODE_04__CLOSE:
wsi->opcode = LWS_WS_OPCODE_07__CLOSE;
break;
case LWS_WS_OPCODE_04__PING:
wsi->opcode = LWS_WS_OPCODE_07__PING;
break;
case LWS_WS_OPCODE_04__PONG:
wsi->opcode = LWS_WS_OPCODE_07__PONG;
break;
case LWS_WS_OPCODE_04__TEXT_FRAME:
wsi->opcode =
LWS_WS_OPCODE_07__TEXT_FRAME;
break;
case LWS_WS_OPCODE_04__BINARY_FRAME:
wsi->opcode =
LWS_WS_OPCODE_07__BINARY_FRAME;
break;
default:
lwsl_warn("reserved opcodes not "
"usable pre v7 protocol\n");
return -1;
}
else
wsi->opcode = c & 0xf;
wsi->rsv = (c & 0x70);
wsi->final = !!((c >> 7) & 1);
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
break;
default:
lwsl_err("client_rx_sm doesn't know how "
"to handle spec version %02d\n",
wsi->ietf_spec_revision);
break;
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN:
if ((c & 0x80) && wsi->ietf_spec_revision < 7) {
lwsl_warn("Frame has extensions set illegally 4\n");
/* kill the connection */
return -1;
}
wsi->this_frame_masked = !!(c & 0x80);
switch (c & 0x7f) {
case 126:
/* control frames are not allowed to have big lengths */
if (wsi->opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
break;
case 127:
/* control frames are not allowed to have big lengths */
if (wsi->opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
break;
default:
wsi->rx_packet_length = c;
if (wsi->this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (c)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
wsi->rx_packet_length = c << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_1:
wsi->rx_packet_length |= c;
if (wsi->this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (wsi->rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
if (c & 0x80) {
lwsl_warn("b63 of length must be zero\n");
/* kill the connection */
return -1;
}
#if defined __LP64__
wsi->rx_packet_length = ((size_t)c) << 56;
#else
wsi->rx_packet_length = 0;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_7:
#if defined __LP64__
wsi->rx_packet_length |= ((size_t)c) << 48;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_6:
#if defined __LP64__
wsi->rx_packet_length |= ((size_t)c) << 40;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_5:
#if defined __LP64__
wsi->rx_packet_length |= ((size_t)c) << 32;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
wsi->rx_packet_length |= ((size_t)c) << 24;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_3:
wsi->rx_packet_length |= ((size_t)c) << 16;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_2:
wsi->rx_packet_length |= ((size_t)c) << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_1:
wsi->rx_packet_length |= (size_t)c;
if (wsi->this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (wsi->rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
wsi->frame_masking_nonce_04[0] = c;
if (c)
wsi->all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
wsi->frame_masking_nonce_04[1] = c;
if (c)
wsi->all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
wsi->frame_masking_nonce_04[2] = c;
if (c)
wsi->all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
wsi->frame_masking_nonce_04[3] = c;
if (c)
wsi->all_zero_nonce = 0;
if (wsi->rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
break;
case LWS_RXPS_EAT_UNTIL_76_FF:
if (c == 0xff) {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto issue;
}
wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->rx_user_buffer_head++)] = c;
if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
break;
issue:
if (wsi->protocol->callback)
wsi->protocol->callback(wsi->protocol->owning_server,
wsi,
LWS_CALLBACK_CLIENT_RECEIVE,
wsi->user_space,
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head);
wsi->rx_user_buffer_head = 0;
break;
case LWS_RXPS_SEEN_76_FF:
if (c)
break;
lwsl_parser("Seen that client is requesting "
"a v76 close, sending ack\n");
buf[0] = 0xff;
buf[1] = 0;
n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP);
if (n < 0) {
lwsl_warn("LWS_RXPS_SEEN_76_FF: ERROR writing to socket\n");
return -1;
}
lwsl_parser(" v76 close ack sent, server closing skt\n");
/* returning < 0 will get it closed in parent */
return -1;
case LWS_RXPS_PULLING_76_LENGTH:
break;
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
if ((!wsi->this_frame_masked) || wsi->all_zero_nonce)
wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->rx_user_buffer_head++)] = c;
else
wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->rx_user_buffer_head++)] =
wsi->xor_mask(wsi, c);
if (--wsi->rx_packet_length == 0) {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
break;
spill:
handled = 0;
/*
* is this frame a control packet we should take care of at this
* layer? If so service it and hide it from the user callback
*/
switch (wsi->opcode) {
case LWS_WS_OPCODE_07__CLOSE:
/* is this an acknowledgement of our close? */
if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
/*
* fine he has told us he is closing too, let's
* finish our close
*/
lwsl_parser("seen server's close ack\n");
return -1;
}
lwsl_parser("client sees server close packet len = %d\n", wsi->rx_user_buffer_head);
/* parrot the close packet payload back */
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head, LWS_WRITE_CLOSE);
lwsl_parser("client writing close ack returned %d\n", n);
wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
/* close the connection */
return -1;
case LWS_WS_OPCODE_07__PING:
/* parrot the ping packet payload back as a pong*/
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head, LWS_WRITE_PONG);
handled = 1;
break;
case LWS_WS_OPCODE_07__PONG:
/* keep the statistics... */
wsi->pings_vs_pongs--;
/* issue it */
callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
break;
case LWS_WS_OPCODE_07__CONTINUATION:
case LWS_WS_OPCODE_07__TEXT_FRAME:
case LWS_WS_OPCODE_07__BINARY_FRAME:
break;
default:
lwsl_parser("Reserved opcode 0x%2X\n", wsi->opcode);
/*
* It's something special we can't understand here.
* Pass the payload up to the extension's parsing
* state machine.
*/
eff_buf.token = &wsi->rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->rx_user_buffer_head;
for (n = 0; n < wsi->count_active_extensions; n++) {
m = wsi->active_extensions[n]->callback(
wsi->protocol->owning_server,
wsi->active_extensions[n], wsi,
LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
wsi->active_extensions_user[n],
&eff_buf, 0);
if (m)
handled = 1;
}
if (!handled) {
lwsl_ext("Unhandled extended opcode "
"0x%x - ignoring frame\n", wsi->opcode);
wsi->rx_user_buffer_head = 0;
return 0;
}
break;
}
/*
* No it's real payload, pass it up to the user callback.
* It's nicely buffered with the pre-padding taken care of
* so it can be sent straight out again using libwebsocket_write
*/
if (handled)
goto already_done;
eff_buf.token = &wsi->rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->rx_user_buffer_head;
for (n = 0; n < wsi->count_active_extensions; n++) {
m = wsi->active_extensions[n]->callback(
wsi->protocol->owning_server,
wsi->active_extensions[n], wsi,
LWS_EXT_CALLBACK_PAYLOAD_RX,
wsi->active_extensions_user[n],
&eff_buf, 0);
if (m < 0) {
lwsl_ext(
"Extension '%s' failed to handle payload!\n",
wsi->active_extensions[n]->name);
return -1;
}
}
if (eff_buf.token_len > 0) {
eff_buf.token[eff_buf.token_len] = '\0';
if (wsi->protocol->callback)
wsi->protocol->callback(
wsi->protocol->owning_server,
wsi,
(enum libwebsocket_callback_reasons)callback_action,
wsi->user_space,
eff_buf.token,
eff_buf.token_len);
}
already_done:
wsi->rx_user_buffer_head = 0;
break;
default:
lwsl_err("client rx illegal state\n");
return 1;
}
return 0;
illegal_ctl_length:
lwsl_warn("Control frame asking for "
"extended length is illegal\n");
/* kill the connection */
return -1;
}
int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,