if LIBCRYPTO
else
-dist_libwebsockets_la_SOURCES += md5.c sha-1.c
+dist_libwebsockets_la_SOURCES += sha-1.c
endif
libwebsockets_la_CFLAGS=-Wall -std=gnu99 -pedantic -g
if (!wsi->c_callback)
wsi->c_callback = context->protocols[0].callback;
- /* set up appropriate masking */
-
- wsi->xor_mask = xor_no_mask;
-
- switch (wsi->ietf_spec_revision) {
- case 0:
- break;
- case 4:
- wsi->xor_mask = xor_mask_04;
- break;
- case 5:
- case 6:
- case 7:
- case 8:
- case 13:
- wsi->xor_mask = xor_mask_05;
- break;
- default:
- lwsl_parser("Client ietf version %d not supported\n",
- wsi->ietf_spec_revision);
- goto oom4;
- }
-
- /* force no mask if he asks for that though */
-
- if (context->options & LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
- wsi->xor_mask = xor_no_mask;
-
for (n = 0; n < WSI_TOKEN_COUNT; n++) {
wsi->utf8_token[n].token = NULL;
wsi->utf8_token[n].token_len = 0;
return __libwebsocket_client_connect_2(context, wsi);
-
-oom4:
- if (wsi->c_protocol)
- free(wsi->c_protocol);
-
oom3:
if (wsi->c_origin)
free(wsi->c_origin);
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;
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;
+ case 13:
+ wsi->opcode = c & 0xf;
wsi->rsv = (c & 0x70);
wsi->final = !!((c >> 7) & 1);
switch (wsi->opcode) {
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) {
}
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 +
else
wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->rx_user_buffer_head++)] =
- wsi->xor_mask(wsi, c);
+ c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3];
if (--wsi->rx_packet_length == 0) {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
lws_client_interpret_server_handshake(struct libwebsocket_context *context,
struct libwebsocket *wsi)
{
- unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 +
- MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
- char pkt[1024];
- char *p = &pkt[0];
const char *pc;
int okay = 0;
#ifndef LWS_NO_EXTENSIONS
int more = 1;
const char *c;
#endif
- int len = 0;
int n;
- static const char magic_websocket_04_masking_guid[] =
- "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
-
- /*
- * 00 / 76 -->
- *
- * HTTP/1.1 101 WebSocket Protocol Handshake
- * Upgrade: WebSocket
- * Connection: Upgrade
- * Sec-WebSocket-Origin: http://127.0.0.1
- * Sec-WebSocket-Location: ws://127.0.0.1:9999/socket.io/websocket
- *
- * xxxxxxxxxxxxxxxx
- */
-
- if (wsi->ietf_spec_revision == 0) {
- if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
- !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
- !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
- !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len
- ) {
- lwsl_parser("libwebsocket_client_handshake "
- "missing required header(s)\n");
- pkt[len] = '\0';
- lwsl_parser("%s", pkt);
- goto bail3;
- }
-
- strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
- if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, "101", 3)) {
- lwsl_warn("libwebsocket_client_handshake "
- "server sent bad HTTP response '%s'\n",
- wsi->utf8_token[WSI_TOKEN_HTTP].token);
- goto bail3;
- }
-
- if (wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len < 16) {
- lwsl_parser("libwebsocket_client_handshake "
- "challenge reply too short %d\n",
- wsi->utf8_token[
- WSI_TOKEN_CHALLENGE].token_len);
- pkt[len] = '\0';
- lwsl_parser("%s", pkt);
- goto bail3;
-
- }
-
- goto select_protocol;
- }
/*
* well, what the server sent looked reasonable for syntax.
lwsl_parser("WSI_TOKEN_PROTOCOL: %d\n",
wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
#endif
- if (!wsi->utf8_token[WSI_TOKEN_HTTP].token_len ||
- !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
- !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
- !wsi->utf8_token[WSI_TOKEN_ACCEPT].token_len ||
- (!wsi->utf8_token[WSI_TOKEN_NONCE].token_len &&
- wsi->ietf_spec_revision == 4)
- ) {
- lwsl_parser("libwebsocket_client_handshake "
- "missing required header(s) revision=%d\n", wsi->ietf_spec_revision);
- pkt[len] = '\0';
- lwsl_parser("%s", pkt);
- goto bail3;
- }
-
- /*
- * Everything seems to be there, now take a closer look at what
- * is in each header
- */
strtolower(wsi->utf8_token[WSI_TOKEN_HTTP].token);
if (strncmp(wsi->utf8_token[WSI_TOKEN_HTTP].token, "101", 3)) {
goto bail3;
}
-select_protocol:
pc = wsi->c_protocol;
if (pc == NULL)
lwsl_parser("lws_client_interpret_server_handshake: "
check_accept:
#endif
- if (wsi->ietf_spec_revision == 0) {
-
- if (memcmp(wsi->initial_handshake_hash_base64,
- wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 16)) {
- lwsl_warn("libwebsocket_client_handshake "
- "failed 00 challenge compare\n");
- pkt[len] = '\0';
- lwsl_warn("%s", pkt);
- goto bail2;
- }
-
- goto accept_ok;
- }
-
/*
* Confirm his accept token is the one we precomputed
*/
goto bail2;
}
- if (wsi->ietf_spec_revision == 4) {
- /*
- * Calculate the 04 masking key to use when
- * sending data to server
- */
-
- strcpy((char *)buf, wsi->key_b64);
- p = (char *)buf + strlen(wsi->key_b64);
- strcpy(p, wsi->utf8_token[WSI_TOKEN_NONCE].token);
- p += wsi->utf8_token[WSI_TOKEN_NONCE].token_len;
- strcpy(p, magic_websocket_04_masking_guid);
- SHA1(buf, strlen((char *)buf), wsi->masking_key_04);
- }
-accept_ok:
-
/* allocate the per-connection user memory (if any) */
if (wsi->protocol->per_session_data_size &&
!libwebsocket_ensure_user_space(wsi))
return 1;
}
-void libwebsockets_00_spaceout(char *key, int spaces, int seed)
-{
- char *p;
-
- key++;
- while (spaces--) {
- if (*key && (seed & 1))
- key++;
- seed >>= 1;
-
- p = key + strlen(key);
- while (p >= key) {
- p[1] = p[0];
- p--;
- }
- *key++ = ' ';
- }
-}
-
-void libwebsockets_00_spam(char *key, int count, int seed)
-{
- char *p;
-
- key++;
- while (count--) {
-
- if (*key && (seed & 1))
- key++;
- seed >>= 1;
-
- p = key + strlen(key);
- while (p >= key) {
- p[1] = p[0];
- p--;
- }
- *key++ = 0x21 + ((seed & 0xffff) % 15);
- /* 4 would use it up too fast.. not like it matters */
- seed >>= 1;
- }
-}
char *
libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
p += sprintf(p, "Pragma: no-cache\x0d\x0a"
"Cache-Control: no-cache\x0d\x0a");
- if (wsi->ietf_spec_revision == 0) {
- unsigned char spaces_1, spaces_2;
- unsigned int max_1, max_2;
- unsigned int num_1, num_2;
- unsigned long product_1, product_2;
- char key_1[40];
- char key_2[40];
- unsigned int seed;
- unsigned int count;
- char challenge[16];
-
- libwebsockets_get_random(context, &spaces_1, sizeof(char));
- libwebsockets_get_random(context, &spaces_2, sizeof(char));
-
- spaces_1 = (spaces_1 % 12) + 1;
- spaces_2 = (spaces_2 % 12) + 1;
-
- max_1 = 4294967295 / spaces_1;
- max_2 = 4294967295 / spaces_2;
-
- libwebsockets_get_random(context, &num_1, sizeof(int));
- libwebsockets_get_random(context, &num_2, sizeof(int));
-
- num_1 = (num_1 % max_1);
- num_2 = (num_2 % max_2);
-
- challenge[0] = num_1 >> 24;
- challenge[1] = num_1 >> 16;
- challenge[2] = num_1 >> 8;
- challenge[3] = num_1;
- challenge[4] = num_2 >> 24;
- challenge[5] = num_2 >> 16;
- challenge[6] = num_2 >> 8;
- challenge[7] = num_2;
-
- product_1 = num_1 * spaces_1;
- product_2 = num_2 * spaces_2;
-
- sprintf(key_1, "%lu", product_1);
- sprintf(key_2, "%lu", product_2);
-
- libwebsockets_get_random(context, &seed, sizeof(int));
- libwebsockets_get_random(context, &count, sizeof(int));
-
- libwebsockets_00_spam(key_1, (count % 12) + 1, seed);
-
- libwebsockets_get_random(context, &seed, sizeof(int));
- libwebsockets_get_random(context, &count, sizeof(int));
-
- libwebsockets_00_spam(key_2, (count % 12) + 1, seed);
-
- libwebsockets_get_random(context, &seed, sizeof(int));
-
- libwebsockets_00_spaceout(key_1, spaces_1, seed);
- libwebsockets_00_spaceout(key_2, spaces_2, seed >> 16);
-
- p += sprintf(p, "Upgrade: WebSocket\x0d\x0a"
- "Connection: Upgrade\x0d\x0aHost: %s\x0d\x0a",
- wsi->c_host);
- if (wsi->c_origin)
- p += sprintf(p, "Origin: %s\x0d\x0a", wsi->c_origin);
-
- if (wsi->c_protocol)
- p += sprintf(p, "Sec-WebSocket-Protocol: %s"
- "\x0d\x0a", wsi->c_protocol);
-
- p += sprintf(p, "Sec-WebSocket-Key1: %s\x0d\x0a", key_1);
- p += sprintf(p, "Sec-WebSocket-Key2: %s\x0d\x0a", key_2);
-
- /* give userland a chance to append, eg, cookies */
-
- context->protocols[0].callback(context, wsi,
- LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
- NULL, &p, (pkt + sizeof(pkt)) - p - 12);
-
- p += sprintf(p, "\x0d\x0a");
-
- if (libwebsockets_get_random(context, p, 8) != 8)
- return NULL;
- memcpy(&challenge[8], p, 8);
- p += 8;
-
- /* precompute what we want to see from the server */
-
- MD5((unsigned char *)challenge, 16,
- (unsigned char *)wsi->initial_handshake_hash_base64);
-
- goto issue_hdr;
- }
-
p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host);
p += sprintf(p, "Upgrade: websocket\x0d\x0a"
"Connection: Upgrade\x0d\x0a"
p += strlen(wsi->key_b64);
p += sprintf(p, "\x0d\x0a");
if (wsi->c_origin) {
- if (wsi->ietf_spec_revision == 13) {
- p += sprintf(p, "Origin: %s\x0d\x0a",
- wsi->c_origin);
- }
- else {
- p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a",
+ if (wsi->ietf_spec_revision == 13)
+ p += sprintf(p, "Origin: %s\x0d\x0a", wsi->c_origin);
+ else
+ p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a",
wsi->c_origin);
- }
- }
+ }
if (wsi->c_protocol)
p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
wsi->c_protocol);
wsi->initial_handshake_hash_base64,
sizeof wsi->initial_handshake_hash_base64);
-issue_hdr:
-
-#if 0
- puts(pkt);
-#endif
-
/* done with these now */
free(wsi->c_path);
#ifndef LWS_NO_SERVER
/* LWS_CONNMODE_WS_SERVING */
- extern int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi);
extern int handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi);
for (n = 0; n < len; n++)
*/
switch (wsi->ietf_spec_revision) {
- case 0: /* applies to 76 and 00 */
- wsi->xor_mask = xor_no_mask;
- if (handshake_00(context, wsi)) {
- lwsl_info("handshake_00 has failed the connection\n");
- goto bail;
- }
- break;
- case 4: /* 04 */
- wsi->xor_mask = xor_mask_04;
- lwsl_parser("libwebsocket_parse calling handshake_04\n");
- if (handshake_0405(context, wsi)) {
- lwsl_info("handshake_0405 has failed the connection\n");
- goto bail;
- }
- break;
- case 5:
- case 6:
- case 7:
- case 8:
case 13:
- wsi->xor_mask = xor_mask_05;
lwsl_parser("libwebsocket_parse calling handshake_04\n");
if (handshake_0405(context, wsi)) {
lwsl_info("handshake_0405 xor 05 has failed the connection\n");
return n;
}
-unsigned char *
-libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md)
-{
- return SHA1(d, n, md);
-}
-
int lws_send_pipe_choked(struct libwebsocket *wsi)
{
struct pollfd fds;
#endif
enum libwebsocket_context_options {
- LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK = 1,
LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2,
LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4,
};
+++ /dev/null
-/*
- * Modified from Polarssl here
- * http://polarssl.org/show_source?file=md5
- * under GPL2 or later
- */
-
-#include <string.h>
-#include <stdio.h>
-
-
-#define GET_ULONG_LE(n, b, i) \
-{ \
- (n) = ((unsigned long)(b)[i]) \
- | ((unsigned long)(b)[(i) + 1] << 8) \
- | ((unsigned long)(b)[(i) + 2] << 16) \
- | ((unsigned long)(b)[(i) + 3] << 24); \
-}
-
-#define PUT_ULONG_LE(n, b, i) \
-{ \
- (b)[i] = (unsigned char)(n); \
- (b)[(i) + 1] = (unsigned char)((n) >> 8); \
- (b)[(i) + 2] = (unsigned char)((n) >> 16); \
- (b)[(i) + 3] = (unsigned char)((n) >> 24); \
-}
-
-static const unsigned char md5_padding[64] = {
- 0x80, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static const unsigned long state_init[] = {
- 0, 0, 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476
-};
-
-static void
-md5_process(unsigned long *state, const unsigned char *data)
-{
- unsigned long X[16], A, B, C, D;
- int v;
-
- for (v = 0; v < 16; v++)
- GET_ULONG_LE(X[v], data, v << 2);
-
-#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
-
-#define P(a, b, c, d, k, s, t) { a += F(b, c, d) + X[k] + t; a = S(a, s) + b; }
-
- A = state[0];
- B = state[1];
- C = state[2];
- D = state[3];
-
-#define F(x, y, z) (z ^ (x & (y ^ z)))
-
- P(A, B, C, D, 0, 7, 0xD76AA478);
- P(D, A, B, C, 1, 12, 0xE8C7B756);
- P(C, D, A, B, 2, 17, 0x242070DB);
- P(B, C, D, A, 3, 22, 0xC1BDCEEE);
- P(A, B, C, D, 4, 7, 0xF57C0FAF);
- P(D, A, B, C, 5, 12, 0x4787C62A);
- P(C, D, A, B, 6, 17, 0xA8304613);
- P(B, C, D, A, 7, 22, 0xFD469501);
- P(A, B, C, D, 8, 7, 0x698098D8);
- P(D, A, B, C, 9, 12, 0x8B44F7AF);
- P(C, D, A, B, 10, 17, 0xFFFF5BB1);
- P(B, C, D, A, 11, 22, 0x895CD7BE);
- P(A, B, C, D, 12, 7, 0x6B901122);
- P(D, A, B, C, 13, 12, 0xFD987193);
- P(C, D, A, B, 14, 17, 0xA679438E);
- P(B, C, D, A, 15, 22, 0x49B40821);
-
-#undef F
-
-#define F(x, y, z) (y ^ (z & (x ^ y)))
-
- P(A, B, C, D, 1, 5, 0xF61E2562);
- P(D, A, B, C, 6, 9, 0xC040B340);
- P(C, D, A, B, 11, 14, 0x265E5A51);
- P(B, C, D, A, 0, 20, 0xE9B6C7AA);
- P(A, B, C, D, 5, 5, 0xD62F105D);
- P(D, A, B, C, 10, 9, 0x02441453);
- P(C, D, A, B, 15, 14, 0xD8A1E681);
- P(B, C, D, A, 4, 20, 0xE7D3FBC8);
- P(A, B, C, D, 9, 5, 0x21E1CDE6);
- P(D, A, B, C, 14, 9, 0xC33707D6);
- P(C, D, A, B, 3, 14, 0xF4D50D87);
- P(B, C, D, A, 8, 20, 0x455A14ED);
- P(A, B, C, D, 13, 5, 0xA9E3E905);
- P(D, A, B, C, 2, 9, 0xFCEFA3F8);
- P(C, D, A, B, 7, 14, 0x676F02D9);
- P(B, C, D, A, 12, 20, 0x8D2A4C8A);
-
-#undef F
-
-#define F(x, y, z) (x ^ y ^ z)
-
- P(A, B, C, D, 5, 4, 0xFFFA3942);
- P(D, A, B, C, 8, 11, 0x8771F681);
- P(C, D, A, B, 11, 16, 0x6D9D6122);
- P(B, C, D, A, 14, 23, 0xFDE5380C);
- P(A, B, C, D, 1, 4, 0xA4BEEA44);
- P(D, A, B, C, 4, 11, 0x4BDECFA9);
- P(C, D, A, B, 7, 16, 0xF6BB4B60);
- P(B, C, D, A, 10, 23, 0xBEBFBC70);
- P(A, B, C, D, 13, 4, 0x289B7EC6);
- P(D, A, B, C, 0, 11, 0xEAA127FA);
- P(C, D, A, B, 3, 16, 0xD4EF3085);
- P(B, C, D, A, 6, 23, 0x04881D05);
- P(A, B, C, D, 9, 4, 0xD9D4D039);
- P(D, A, B, C, 12, 11, 0xE6DB99E5);
- P(C, D, A, B, 15, 16, 0x1FA27CF8);
- P(B, C, D, A, 2, 23, 0xC4AC5665);
-
-#undef F
-
-#define F(x, y, z) (y ^ (x | ~z))
-
- P(A, B, C, D, 0, 6, 0xF4292244);
- P(D, A, B, C, 7, 10, 0x432AFF97);
- P(C, D, A, B, 14, 15, 0xAB9423A7);
- P(B, C, D, A, 5, 21, 0xFC93A039);
- P(A, B, C, D, 12, 6, 0x655B59C3);
- P(D, A, B, C, 3, 10, 0x8F0CCC92);
- P(C, D, A, B, 10, 15, 0xFFEFF47D);
- P(B, C, D, A, 1, 21, 0x85845DD1);
- P(A, B, C, D, 8, 6, 0x6FA87E4F);
- P(D, A, B, C, 15, 10, 0xFE2CE6E0);
- P(C, D, A, B, 6, 15, 0xA3014314);
- P(B, C, D, A, 13, 21, 0x4E0811A1);
- P(A, B, C, D, 4, 6, 0xF7537E82);
- P(D, A, B, C, 11, 10, 0xBD3AF235);
- P(C, D, A, B, 2, 15, 0x2AD7D2BB);
- P(B, C, D, A, 9, 21, 0xEB86D391);
-
-#undef F
-
- state[0] += A;
- state[1] += B;
- state[2] += C;
- state[3] += D;
-}
-
-static
-void md5_update(unsigned long *state, unsigned char *buffer,
- const unsigned char *input, int ilen)
-{
- int fill;
- unsigned long left;
-
- if (ilen <= 0)
- return;
-
- left = state[0] & 0x3F;
- fill = 64 - left;
-
- state[0] += ilen;
- state[0] &= 0xFFFFFFFF;
-
- if (state[0] < (unsigned long)ilen)
- state[1]++;
-
- if (left && ilen >= fill) {
- memcpy(buffer + left, input, fill);
- md5_process(&state[2], buffer);
- input += fill;
- ilen -= fill;
- left = 0;
- }
-
- while (ilen >= 64) {
- md5_process(&state[2], input);
- input += 64;
- ilen -= 64;
- }
-
- if (ilen > 0)
- memcpy(buffer + left, input, ilen);
-}
-
-void
-MD5(const unsigned char *input, int ilen, unsigned char *output)
-{
- unsigned long last, padn;
- unsigned long high, low;
- unsigned char msglen[8];
- unsigned long state[6];
- unsigned char buffer[64];
-
- memcpy(&state[0], &state_init[0], sizeof(state_init));
-
- md5_update(state, buffer, input, ilen);
-
- high = (state[0] >> 29) | (state[1] << 3);
- low = state[0] << 3;
-
- PUT_ULONG_LE(low, msglen, 0);
- PUT_ULONG_LE(high, msglen, 4);
-
- last = state[0] & 0x3F;
- padn = (last < 56) ? (56 - last) : (120 - last);
-
- md5_update(state, buffer, md5_padding, padn);
- md5_update(state, buffer, msglen, 8);
-
- PUT_ULONG_LE(state[2], output, 0);
- PUT_ULONG_LE(state[3], output, 4);
- PUT_ULONG_LE(state[4], output, 8);
- PUT_ULONG_LE(state[5], output, 12);
-}
-
static int
libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi)
{
- char buf[4 + 20];
int n;
/* fetch the per-frame nonce */
/* start masking from first byte of masking key buffer */
wsi->frame_mask_index = 0;
- if (wsi->ietf_spec_revision != 4)
- return 0;
-
- /* 04 only does SHA-1 more complex key */
-
- /*
- * the frame key is the frame nonce (4 bytes) followed by the
- * connection masking key, hashed by SHA1
- */
-
- memcpy(buf, wsi->frame_masking_nonce_04, 4);
-
- memcpy(buf + 4, wsi->masking_key_04, 20);
-
- /* concatenate the nonce with the connection key then hash it */
-
- SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04);
-
return 0;
}
int n;
int pre = 0;
int post = 0;
- int shift = 7;
- int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT &&
- wsi->xor_mask != xor_no_mask;
+ int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT;
unsigned char *dropmask = NULL;
unsigned char is_masked_bit = 0;
#ifndef LWS_NO_EXTENSIONS
#endif
switch (wsi->ietf_spec_revision) {
- /* chrome likes this as of 30 Oct 2010 */
- /* Firefox 4.0b6 likes this as of 30 Oct 2010 */
- case 0:
- if ((protocol & 0xf) == LWS_WRITE_BINARY) {
- /* in binary mode we send 7-bit used length blocks */
- pre = 1;
- while (len & (127 << shift)) {
- pre++;
- shift += 7;
- }
- n = 0;
- shift -= 7;
- while (shift >= 0) {
- if (shift)
- buf[0 - pre + n] =
- ((len >> shift) & 127) | 0x80;
- else
- buf[0 - pre + n] =
- ((len >> shift) & 127);
- n++;
- shift -= 7;
- }
- break;
- }
-
- /* frame type = text, length-free spam mode */
-
- pre = 1;
- buf[-pre] = 0;
- buf[len] = 0xff; /* EOT marker */
- post = 1;
- break;
-
- case 7:
- case 8:
case 13:
if (masked7) {
pre += 4;
dropmask = &buf[0 - pre];
is_masked_bit = 0x80;
}
- /* fallthru */
- case 4:
- case 5:
- case 6:
+
switch (protocol & 0xf) {
case LWS_WRITE_TEXT:
- if (wsi->ietf_spec_revision < 7)
- n = LWS_WS_OPCODE_04__TEXT_FRAME;
- else
- n = LWS_WS_OPCODE_07__TEXT_FRAME;
+ n = LWS_WS_OPCODE_07__TEXT_FRAME;
break;
case LWS_WRITE_BINARY:
- if (wsi->ietf_spec_revision < 7)
- n = LWS_WS_OPCODE_04__BINARY_FRAME;
- else
- n = LWS_WS_OPCODE_07__BINARY_FRAME;
+ n = LWS_WS_OPCODE_07__BINARY_FRAME;
break;
case LWS_WRITE_CONTINUATION:
- if (wsi->ietf_spec_revision < 7)
- n = LWS_WS_OPCODE_04__CONTINUATION;
- else
- n = LWS_WS_OPCODE_07__CONTINUATION;
+ n = LWS_WS_OPCODE_07__CONTINUATION;
break;
case LWS_WRITE_CLOSE:
- if (wsi->ietf_spec_revision < 7)
- n = LWS_WS_OPCODE_04__CLOSE;
- else
- n = LWS_WS_OPCODE_07__CLOSE;
+ n = LWS_WS_OPCODE_07__CLOSE;
/*
- * v5 mandates the first byte of close packet
- * in both client and server directions
+ * 06+ has a 2-byte status code in network order
+ * we can do this because we demand post-buf
*/
- switch (wsi->ietf_spec_revision) {
- case 0:
- case 4:
- break;
- case 5:
- /* we can do this because we demand post-buf */
-
- if (len < 1)
- len = 1;
-
- switch (wsi->mode) {
- case LWS_CONNMODE_WS_SERVING:
- /*
- lwsl_debug("LWS_WRITE_CLOSE S\n");
- */
- buf[0] = 'S';
- break;
- case LWS_CONNMODE_WS_CLIENT:
- /*
- lwsl_debug("LWS_WRITE_CLOSE C\n");
- */
- buf[0] = 'C';
- break;
- default:
- break;
- }
- break;
- default:
- /*
- * 06 has a 2-byte status code in network order
- * we can do this because we demand post-buf
- */
-
- if (wsi->close_reason) {
- /* reason codes count as data bytes */
- buf -= 2;
- buf[0] = wsi->close_reason >> 8;
- buf[1] = wsi->close_reason;
- len += 2;
- }
- break;
+ if (wsi->close_reason) {
+ /* reason codes count as data bytes */
+ buf -= 2;
+ buf[0] = wsi->close_reason >> 8;
+ buf[1] = wsi->close_reason;
+ len += 2;
}
break;
case LWS_WRITE_PING:
- if (wsi->ietf_spec_revision < 7)
- n = LWS_WS_OPCODE_04__PING;
- else
- n = LWS_WS_OPCODE_07__PING;
-
+ n = LWS_WS_OPCODE_07__PING;
wsi->pings_vs_pongs++;
break;
case LWS_WRITE_PONG:
- if (wsi->ietf_spec_revision < 7)
- n = LWS_WS_OPCODE_04__PONG;
- else
- n = LWS_WS_OPCODE_07__PONG;
+ n = LWS_WS_OPCODE_07__PONG;
break;
default:
lwsl_warn("libwebsocket_write: unknown write "
* the protocol demands it
*/
- if (wsi->mode == LWS_CONNMODE_WS_CLIENT &&
- wsi->ietf_spec_revision >= 4) {
+ if (wsi->mode == LWS_CONNMODE_WS_CLIENT) {
+
+ if (libwebsocket_0405_frame_mask_generate(wsi)) {
+ lwsl_err("libwebsocket_write: "
+ "frame mask generation failed\n");
+ return 1;
+ }
/*
- * this is only useful for security tests where it's required
- * to control the raw packet payload content
+ * in v7, just mask the payload
*/
+ for (n = 4; n < (int)len + 4; n++)
+ dropmask[n] = dropmask[n] ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3];
- if (!(protocol & LWS_WRITE_CLIENT_IGNORE_XOR_MASK) &&
- wsi->xor_mask != xor_no_mask) {
-
- if (libwebsocket_0405_frame_mask_generate(wsi)) {
- lwsl_err("libwebsocket_write: "
- "frame mask generation failed\n");
- return 1;
- }
-
-
- if (wsi->ietf_spec_revision < 7)
- /*
- * use the XOR masking against everything we
- * send past the frame key
- */
- for (n = -pre; n < ((int)len + post); n++)
- buf[n] = wsi->xor_mask(wsi, buf[n]);
- else
- /*
- * in v7, just mask the payload
- */
- for (n = 0; n < (int)len; n++)
- dropmask[n + 4] =
- wsi->xor_mask(wsi, dropmask[n + 4]);
-
-
- if (wsi->ietf_spec_revision < 7) {
- /* make space for the frame nonce in clear */
- pre += 4;
-
- dropmask = &buf[0 - pre];
- }
-
- if (dropmask)
- /* copy the frame nonce into place */
- memcpy(dropmask,
- wsi->frame_masking_nonce_04, 4);
-
- } else {
- if (wsi->ietf_spec_revision < 7) {
-
- /* make space for the frame nonce in clear */
- pre += 4;
-
- buf[0 - pre] = 0;
- buf[1 - pre] = 0;
- buf[2 - pre] = 0;
- buf[3 - pre] = 0;
- } else {
- if (dropmask && wsi->xor_mask != xor_no_mask) {
- dropmask[0] = 0;
- dropmask[1] = 0;
- dropmask[2] = 0;
- dropmask[3] = 0;
- }
- }
- }
-
+ if (dropmask)
+ /* copy the frame nonce into place */
+ memcpy(dropmask,
+ wsi->frame_masking_nonce_04, 4);
}
send_raw:
/* client parser? */
- if (wsi->ietf_spec_revision >= 4) {
- lwsl_parser("04 header completed\n");
- wsi->parser_state = WSI_PARSING_COMPLETE;
- }
+ lwsl_parser("04 header completed\n");
+ wsi->parser_state = WSI_PARSING_COMPLETE;
break;
return 0;
}
-unsigned char
-xor_no_mask(struct libwebsocket *wsi, unsigned char c)
-{
- return c;
-}
-
-unsigned char
-xor_mask_04(struct libwebsocket *wsi, unsigned char c)
-{
- c ^= wsi->masking_key_04[wsi->frame_mask_index++];
- if (wsi->frame_mask_index == 20)
- wsi->frame_mask_index = 0;
-
- return c;
-}
-
-unsigned char
-xor_mask_05(struct libwebsocket *wsi, unsigned char c)
-{
- return c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3];
-}
/**
* lws_frame_is_binary: true if the current frame was sent in binary mode
libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
{
int n;
- unsigned char buf[20 + 4];
struct lws_tokens eff_buf;
#ifndef LWS_NO_EXTENSIONS
int handled;
case LWS_RXPS_NEW:
switch (wsi->ietf_spec_revision) {
- /* Firefox 4.0b6 likes this as of 30 Oct 2010 */
- 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:
- wsi->all_zero_nonce = 1;
- wsi->frame_masking_nonce_04[0] = c;
- if (c)
- wsi->all_zero_nonce = 0;
- wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_1;
- break;
- case 7:
- case 8:
case 13:
/*
* no prepended frame key any more
if (c)
wsi->all_zero_nonce = 0;
- if (wsi->protocol->owning_server->options &
- LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
- goto post_mask;
-
- if (wsi->ietf_spec_revision > 4)
- goto post_sha1;
-
- /*
- * we are able to compute the frame key now
- * it's a SHA1 of ( frame nonce we were just sent, concatenated
- * with the connection masking key we computed at handshake
- * time ) -- yeah every frame from the client invokes a SHA1
- * for no real reason so much for lightweight.
- */
-
- buf[0] = wsi->frame_masking_nonce_04[0];
- buf[1] = wsi->frame_masking_nonce_04[1];
- buf[2] = wsi->frame_masking_nonce_04[2];
- buf[3] = wsi->frame_masking_nonce_04[3];
-
- memcpy(buf + 4, wsi->masking_key_04, 20);
-
- /*
- * wsi->frame_mask_04 will be our recirculating 20-byte XOR key
- * for this frame
- */
-
- SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04);
-
-post_sha1:
-
/*
* start from the zero'th byte in the XOR key buffer since
* this is the start of a frame with a new key
wsi->frame_mask_index = 0;
-post_mask:
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
break;
* FIN (b7)
*/
- if (wsi->ietf_spec_revision < 7)
- c = wsi->xor_mask(wsi, c);
-
- /* translate all incoming opcodes into v7+ map */
- 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->opcode = c & 0xf;
+ wsi->rsv = c & 0x70;
wsi->final = !!((c >> 7) & 1);
switch (wsi->opcode) {
case LWS_WS_OPCODE_07__TEXT_FRAME:
case LWS_RXPS_04_FRAME_HDR_LEN:
- if (wsi->ietf_spec_revision < 7)
- c = wsi->xor_mask(wsi, c);
-
- if ((c & 0x80) && wsi->ietf_spec_revision < 7) {
- lwsl_warn("Frame has extensions set illegally 2\n");
- /* kill the connection */
- return -1;
- }
-
wsi->this_frame_masked = !!(c & 0x80);
switch (c & 0x7f) {
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
- 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:
- if (wsi->ietf_spec_revision < 7)
- c = wsi->xor_mask(wsi, c);
-
wsi->rx_packet_length |= c;
if (wsi->this_frame_masked)
wsi->lws_rx_parse_state =
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
- if (wsi->ietf_spec_revision < 7)
- c = wsi->xor_mask(wsi, c);
if (c & 0x80) {
lwsl_warn("b63 of length must be zero\n");
/* kill the connection */
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)c) << 48;
#endif
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)c) << 40;
#endif
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)c) << 32;
#endif
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
- 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:
- 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:
- 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:
- 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_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
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)
- user_callback_handle_rxflow(wsi->protocol->callback,
- wsi->protocol->owning_server,
- wsi, LWS_CALLBACK_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("ERROR writing to socket");
- 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_07_COLLECT_FRAME_KEY_1:
wsi->frame_masking_nonce_04[0] = c;
if (c)
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
- if (wsi->ietf_spec_revision < 4 ||
- (wsi->all_zero_nonce && wsi->ietf_spec_revision >= 5))
+ if (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);
+ c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3];
if (--wsi->rx_packet_length == 0) {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
*/
#define LWS_LISTEN_SERVICE_MODULO 10
-enum lws_websocket_opcodes_04 {
- LWS_WS_OPCODE_04__CONTINUATION = 0,
- LWS_WS_OPCODE_04__CLOSE = 1,
- LWS_WS_OPCODE_04__PING = 2,
- LWS_WS_OPCODE_04__PONG = 3,
- LWS_WS_OPCODE_04__TEXT_FRAME = 4,
- LWS_WS_OPCODE_04__BINARY_FRAME = 5,
-
- LWS_WS_OPCODE_04__RESERVED_6 = 6,
- LWS_WS_OPCODE_04__RESERVED_7 = 7,
- LWS_WS_OPCODE_04__RESERVED_8 = 8,
- LWS_WS_OPCODE_04__RESERVED_9 = 9,
- LWS_WS_OPCODE_04__RESERVED_A = 0xa,
- LWS_WS_OPCODE_04__RESERVED_B = 0xb,
- LWS_WS_OPCODE_04__RESERVED_C = 0xc,
- LWS_WS_OPCODE_04__RESERVED_D = 0xd,
- LWS_WS_OPCODE_04__RESERVED_E = 0xe,
- LWS_WS_OPCODE_04__RESERVED_F = 0xf,
-};
-
enum lws_websocket_opcodes_07 {
LWS_WS_OPCODE_07__CONTINUATION = 0,
LWS_WS_OPCODE_07__TEXT_FRAME = 1,
enum lws_rx_parse_state {
LWS_RXPS_NEW,
- LWS_RXPS_SEEN_76_FF,
- LWS_RXPS_PULLING_76_LENGTH,
- LWS_RXPS_EAT_UNTIL_76_FF,
-
LWS_RXPS_04_MASK_NONCE_1,
LWS_RXPS_04_MASK_NONCE_2,
LWS_RXPS_04_MASK_NONCE_3,
int frame_is_binary:1;
int pings_vs_pongs;
- unsigned char (*xor_mask)(struct libwebsocket *, unsigned char);
char all_zero_nonce;
enum lws_close_status close_reason;
extern int
lws_b64_selftest(void);
-extern unsigned char
-xor_no_mask(struct libwebsocket *wsi, unsigned char c);
-
-extern unsigned char
-xor_mask_04(struct libwebsocket *wsi, unsigned char c);
-
-extern unsigned char
-xor_mask_05(struct libwebsocket *wsi, unsigned char c);
-
extern struct libwebsocket *
wsi_from_fd(struct libwebsocket_context *context, int fd);
#define LWS_CPYAPP_TOKEN(ptr, tok) { strcpy(p, wsi->utf8_token[tok].token); \
p += wsi->utf8_token[tok].token_len; }
-static int
-interpret_key(const char *key, unsigned long *result)
-{
- char digits[20];
- int digit_pos = 0;
- const char *p = key;
- unsigned int spaces = 0;
- unsigned long acc = 0;
- int rem = 0;
-
- while (*p) {
- if (!isdigit(*p)) {
- p++;
- continue;
- }
- if (digit_pos == sizeof(digits) - 1)
- return -1;
- digits[digit_pos++] = *p++;
- }
- digits[digit_pos] = '\0';
- if (!digit_pos)
- return -2;
-
- while (*key) {
- if (*key == ' ')
- spaces++;
- key++;
- }
-
- if (!spaces)
- return -3;
-
- p = &digits[0];
- while (*p) {
- rem = (rem * 10) + ((*p++) - '0');
- acc = (acc * 10) + (rem / spaces);
- rem -= (rem / spaces) * spaces;
- }
-
- if (rem) {
- lwsl_warn("nonzero handshake remainder\n");
- return -1;
- }
-
- *result = acc;
-
- return 0;
-}
-
-
-int handshake_00(struct libwebsocket_context *context, struct libwebsocket *wsi)
-{
- unsigned long key1, key2;
- unsigned char sum[16];
- char *response;
- char *p;
- int n;
-
- /* Confirm we have all the necessary pieces */
-
- if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
- !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
- !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
- !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
- !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
- /* completed header processing, but missing some bits */
- goto bail;
-
- /* allocate the per-connection user memory (if any) */
- if (wsi->protocol->per_session_data_size &&
- !libwebsocket_ensure_user_space(wsi))
- goto bail;
-
- /* create the response packet */
-
- /* make a buffer big enough for everything */
-
- response = (char *)malloc(256 +
- wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
- wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
- wsi->utf8_token[WSI_TOKEN_HOST].token_len +
- wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
- wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
- wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
- if (!response) {
- lwsl_err("Out of memory for response buffer\n");
- goto bail;
- }
-
- p = response;
- LWS_CPYAPP(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
- "Upgrade: WebSocket\x0d\x0a"
- "Connection: Upgrade\x0d\x0a"
- "Sec-WebSocket-Origin: ");
- strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
- p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
-#ifdef LWS_OPENSSL_SUPPORT
- if (wsi->ssl) {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: wss://");
- } else {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
- }
-#else
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Location: ws://");
-#endif
-
- LWS_CPYAPP_TOKEN(p, WSI_TOKEN_HOST);
- LWS_CPYAPP_TOKEN(p, WSI_TOKEN_GET_URI);
-
- if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
- LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
- }
-
- LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
-
- /* convert the two keys into 32-bit integers */
-
- if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
- goto bail;
- if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
- goto bail;
-
- /* lay them out in network byte order (MSB first */
-
- sum[0] = (unsigned char)(key1 >> 24);
- sum[1] = (unsigned char)(key1 >> 16);
- sum[2] = (unsigned char)(key1 >> 8);
- sum[3] = (unsigned char)(key1);
- sum[4] = (unsigned char)(key2 >> 24);
- sum[5] = (unsigned char)(key2 >> 16);
- sum[6] = (unsigned char)(key2 >> 8);
- sum[7] = (unsigned char)(key2);
-
- /* follow them with the challenge token we were sent */
-
- memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
-
- /*
- * compute the md5sum of that 16-byte series and use as our
- * payload after our headers
- */
-
- MD5(sum, 16, (unsigned char *)p);
- p += 16;
-
- /* it's complete: go ahead and send it */
-
- lwsl_parser("issuing response packet %d len\n", (int)(p - response));
-#ifdef _DEBUG
- fwrite(response, 1, p - response, stderr);
-#endif
- n = libwebsocket_write(wsi, (unsigned char *)response,
- p - response, LWS_WRITE_HTTP);
- if (n < 0) {
- lwsl_debug("handshake_00: ERROR writing to socket\n");
- goto bail;
- }
-
- /* alright clean up and set ourselves into established state */
-
- free(response);
- wsi->state = WSI_STATE_ESTABLISHED;
- wsi->lws_rx_parse_state = LWS_RXPS_NEW;
-
- /* notify user code that we're ready to roll */
-
- if (wsi->protocol->callback)
- wsi->protocol->callback(wsi->protocol->owning_server,
- wsi, LWS_CALLBACK_ESTABLISHED,
- wsi->user_space, NULL, 0);
-
- return 0;
-
-bail:
- return -1;
-}
-
/*
* Perform the newer BASE64-encoded handshake scheme
*/
{
static const char *websocket_magic_guid_04 =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- static const char *websocket_magic_guid_04_masking =
- "61AC5F19-FBBA-4540-B96F-6561F1AB40A8";
char accept_buf[MAX_WEBSOCKET_04_KEY_LEN + 37];
- char nonce_buf[256];
- char mask_summing_buf[256 + MAX_WEBSOCKET_04_KEY_LEN + 37];
unsigned char hash[20];
int n;
char *response;
char *p;
- char *m = mask_summing_buf;
- int nonce_len = 0;
int accept_len;
#ifndef LWS_NO_EXTENSIONS
char *c;
strcpy(p, accept_buf);
p += accept_len;
- if (wsi->ietf_spec_revision == 4) {
- LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Nonce: ");
-
- /* select the nonce */
-
- n = libwebsockets_get_random(wsi->protocol->owning_server,
- hash, 16);
- if (n != 16) {
- lwsl_err("Unable to read random device %s %d\n",
- SYSTEM_RANDOM_FILEPATH, n);
- if (wsi->user_space)
- free(wsi->user_space);
- goto bail;
- }
-
- /* encode the nonce */
-
- nonce_len = lws_b64_encode_string((const char *)hash, 16,
- nonce_buf, sizeof nonce_buf);
- if (nonce_len < 0) {
- lwsl_err("Failed to base 64 encode the nonce\n");
- if (wsi->user_space)
- free(wsi->user_space);
- goto bail;
- }
-
- /* apply the nonce */
-
- strcpy(p, nonce_buf);
- p += nonce_len;
- }
-
if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
LWS_CPYAPP_TOKEN(p, WSI_TOKEN_PROTOCOL);
LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
- if (wsi->ietf_spec_revision == 4) {
-
- /*
- * precompute the masking key the client will use from the SHA1
- * hash of ( base 64 client key we were sent, concatenated with
- * the bse 64 nonce we sent, concatenated with a magic constant
- * guid specified by the 04 standard )
- *
- * We store the hash in the connection's wsi ready to use with
- * undoing the masking the client has done on framed data it
- * sends (we send our data to the client in clear).
- */
-
- strcpy(mask_summing_buf, wsi->utf8_token[WSI_TOKEN_KEY].token);
- m += wsi->utf8_token[WSI_TOKEN_KEY].token_len;
- strcpy(m, nonce_buf);
- m += nonce_len;
- strcpy(m, websocket_magic_guid_04_masking);
- m += strlen(websocket_magic_guid_04_masking);
-
- SHA1((unsigned char *)mask_summing_buf, m - mask_summing_buf,
- wsi->masking_key_04);
- }
-
#ifndef LWS_NO_EXTENSIONS
if (!lws_any_extension_handled(context, wsi,
LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
- { "killmask", no_argument, NULL, 'k' },
{ "version", required_argument, NULL, 'v' },
{ "undeflated", no_argument, NULL, 'u' },
{ "nomux", no_argument, NULL, 'n' },
goto usage;
while (n >= 0) {
- n = getopt_long(argc, argv, "nuv:khsp:d:l", options, NULL);
+ n = getopt_long(argc, argv, "nuv:hsp:d:l", options, NULL);
if (n < 0)
continue;
switch (n) {
case 'l':
longlived = 1;
break;
- case 'k':
- opts = LWS_WRITE_CLIENT_IGNORE_XOR_MASK;
- break;
case 'v':
ietf_version = atoi(optarg);
break;
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
- { "killmask", no_argument, NULL, 'k' },
{ "interface", required_argument, NULL, 'i' },
{ "client", no_argument, NULL, 'c' },
{ NULL, 0, 0, 0 }
int server_port = port;
fprintf(stderr, "libwebsockets test fraggle\n"
- "(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> "
+ "(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> "
"licensed under LGPL2.1\n");
while (n >= 0) {
- n = getopt_long(argc, argv, "ci:khsp:d:", options, NULL);
+ n = getopt_long(argc, argv, "ci:hsp:d:", options, NULL);
if (n < 0)
continue;
switch (n) {
case 's':
use_ssl = 1;
break;
- case 'k':
- opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK;
- break;
case 'p':
port = atoi(optarg);
server_port = port;
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
- { "killmask", no_argument, NULL, 'k' },
{ "interface", required_argument, NULL, 'i' },
{ "closetest", no_argument, NULL, 'c' },
#ifndef NO_DAEMONIZE
#endif
while (n >= 0) {
- n = getopt_long(argc, argv, "ci:khsp:d:D", options, NULL);
+ n = getopt_long(argc, argv, "ci:hsp:d:D", options, NULL);
if (n < 0)
continue;
switch (n) {
case 's':
use_ssl = 1;
break;
- case 'k':
- opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK;
- break;
case 'p':
port = atoi(optarg);
break;