From 283d0a2046d7e29c73be5c07a03ae046f8ab0df7 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sun, 24 Apr 2011 05:46:23 +0100 Subject: [PATCH] add 07 support Signed-off-by: Andy Green --- lib/parsers.c | 170 ++++++++++++++++++++++++++++++++++++++------ lib/private-libwebsockets.h | 10 ++- 2 files changed, 157 insertions(+), 23 deletions(-) diff --git a/lib/parsers.c b/lib/parsers.c index 4f1c792..263b36d 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -297,6 +297,16 @@ static int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) wsi->all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_1; break; + case 7: + /* + * no prepended frame key any more + */ + wsi->all_zero_nonce = 1; + wsi->frame_masking_nonce_04[0] = c; + if (c) + wsi->all_zero_nonce = 0; + goto handle_first; + default: fprintf(stderr, "libwebsocket_rx_sm doesn't know " "about spec version %d\n", wsi->ietf_spec_revision); @@ -393,6 +403,8 @@ post_mask: */ case LWS_RXPS_04_FRAME_HDR_1: +handle_first: + /* * 04 spec defines the opcode like this: (1, 2, and 3 are * "control frame" opcodes which may not be fragmented or @@ -410,7 +422,8 @@ post_mask: * FIN (b7) */ - c = wsi->xor_mask(wsi, c); + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); if (c & 0x70) { fprintf(stderr, @@ -426,15 +439,19 @@ post_mask: break; case LWS_RXPS_04_FRAME_HDR_LEN: - c = wsi->xor_mask(wsi, c); - if (c & 0x80) { + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + + if ((c & 0x80) && wsi->ietf_spec_revision < 7) { fprintf(stderr, "Frame has extensions " "set illegally 2\n"); /* kill the connection */ return -1; } + wsi->this_frame_masked = !!(c & 0x80); + switch (c) { case 126: /* control frames are not allowed to have big lengths */ @@ -468,29 +485,40 @@ post_mask: break; default: wsi->rx_packet_length = c; - wsi->lws_rx_parse_state = + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; } break; case LWS_RXPS_04_FRAME_HDR_LEN16_2: - c = wsi->xor_mask(wsi, c); + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); 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: - c = wsi->xor_mask(wsi, c); + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); wsi->rx_packet_length |= c; - wsi->lws_rx_parse_state = - LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; case LWS_RXPS_04_FRAME_HDR_LEN64_8: - c = wsi->xor_mask(wsi, c); + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); if (c & 0x80) { fprintf(stderr, "b63 of length must be zero\n"); /* kill the connection */ @@ -505,45 +533,63 @@ post_mask: break; case LWS_RXPS_04_FRAME_HDR_LEN64_7: + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); #if defined __LP64__ - wsi->rx_packet_length |= ((size_t)wsi->xor_mask(wsi, c)) << 48; + 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 (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); #if defined __LP64__ - wsi->rx_packet_length |= ((size_t)wsi->xor_mask(wsi, c)) << 40; + 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 (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); #if defined __LP64__ - wsi->rx_packet_length |= ((size_t)wsi->xor_mask(wsi, c)) << 32; + 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)wsi->xor_mask(wsi, c)) << 24; + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + 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)wsi->xor_mask(wsi, c)) << 16; + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + 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)wsi->xor_mask(wsi, c)) << 8; + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + 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)wsi->xor_mask(wsi, c)); - wsi->lws_rx_parse_state = - LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + if (wsi->ietf_spec_revision < 7) + c = wsi->xor_mask(wsi, c); + 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 + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; case LWS_RXPS_EAT_UNTIL_76_FF: @@ -585,6 +631,37 @@ issue: case LWS_RXPS_PULLING_76_LENGTH: 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; + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + break; + + case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: if (wsi->all_zero_nonce && wsi->ietf_spec_revision >= 5) wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + @@ -692,6 +769,7 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) case 4: case 5: case 6: + case 7: /* * 04 logical framing from the spec (all this is masked when * incoming and has to be unmasked) @@ -720,6 +798,10 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) * 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. */ /* @@ -751,6 +833,7 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN; break; + default: fprintf(stderr, "client_rx_sm doesn't know how " "to handle spec version %02d\n", @@ -762,13 +845,15 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_RXPS_04_FRAME_HDR_LEN: - if (c & 0x80) { + if ((c & 0x80) && wsi->ietf_spec_revision < 7) { fprintf(stderr, "Frame has extensions set illegally 4\n"); /* kill the connection */ return -1; } + wsi->this_frame_masked = !!(c & 0x80); + switch (c) { case 126: /* control frames are not allowed to have big lengths */ @@ -802,7 +887,11 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) break; default: wsi->rx_packet_length = c; - wsi->lws_rx_parse_state = + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; } @@ -815,8 +904,12 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_RXPS_04_FRAME_HDR_LEN16_1: wsi->rx_packet_length |= c; - wsi->lws_rx_parse_state = - LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + if (wsi->this_frame_masked) + wsi->lws_rx_parse_state = + LWS_RXPS_07_COLLECT_FRAME_KEY_1; + else + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; case LWS_RXPS_04_FRAME_HDR_LEN64_8: @@ -871,6 +964,39 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) 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 + wsi->lws_rx_parse_state = + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; + 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; wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 5a93327..4b4d3cd 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -109,7 +109,7 @@ static inline void debug(const char *format, ...) #define MAX_BROADCAST_PAYLOAD 2048 #define LWS_MAX_PROTOCOLS 10 #define LWS_MAX_EXTENSIONS_ACTIVE 10 -#define SPEC_LATEST_SUPPORTED 6 +#define SPEC_LATEST_SUPPORTED 7 #define MAX_WEBSOCKET_04_KEY_LEN 128 #define SYSTEM_RANDOM_FILEPATH "/dev/urandom" @@ -166,6 +166,11 @@ enum lws_rx_parse_state { LWS_RXPS_04_FRAME_HDR_LEN64_2, LWS_RXPS_04_FRAME_HDR_LEN64_1, + LWS_RXPS_07_COLLECT_FRAME_KEY_1, + LWS_RXPS_07_COLLECT_FRAME_KEY_2, + LWS_RXPS_07_COLLECT_FRAME_KEY_3, + LWS_RXPS_07_COLLECT_FRAME_KEY_4, + LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED }; @@ -279,6 +284,9 @@ struct libwebsocket { enum lws_close_status close_reason; + /* 07 specific */ + char this_frame_masked; + /* client support */ char initial_handshake_hash_base64[30]; enum connection_mode mode; -- 2.7.4