diff options
Diffstat (limited to 'jerry-core/debugger/debugger-ws.c')
-rw-r--r-- | jerry-core/debugger/debugger-ws.c | 451 |
1 files changed, 0 insertions, 451 deletions
diff --git a/jerry-core/debugger/debugger-ws.c b/jerry-core/debugger/debugger-ws.c deleted file mode 100644 index d980b9b7..00000000 --- a/jerry-core/debugger/debugger-ws.c +++ /dev/null @@ -1,451 +0,0 @@ -/* Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "debugger-ws.h" -#include "jrt.h" - -#ifdef JERRY_DEBUGGER - -/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */ - -/** - * Last fragment of a Websocket package. - */ -#define JERRY_DEBUGGER_WEBSOCKET_FIN_BIT 0x80 - -/** - * Masking-key is available. - */ -#define JERRY_DEBUGGER_WEBSOCKET_MASK_BIT 0x80 - -/** - * Opcode type mask. - */ -#define JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK 0x0fu - -/** - * Packet length mask. - */ -#define JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK 0x7fu - -/** - * Size of websocket header size. - */ -#define JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE 2 - -/** - * Payload mask size in bytes of a websocket package. - */ -#define JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE 4 - -/** - * Maximum message size with 1 byte size field. - */ -#define JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX 125 - -/** - * WebSocket opcode types. - */ -typedef enum -{ - JERRY_DEBUGGER_WEBSOCKET_TEXT_FRAME = 1, /**< text frame */ - JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME = 2, /**< binary frame */ - JERRY_DEBUGGER_WEBSOCKET_CLOSE_CONNECTION = 8, /**< close connection */ - JERRY_DEBUGGER_WEBSOCKET_PING = 9, /**< ping (keep alive) frame */ - JERRY_DEBUGGER_WEBSOCKET_PONG = 10, /**< reply to ping frame */ -} jerry_websocket_opcode_type_t; - -/** - * Header for incoming packets. - */ -typedef struct -{ - uint8_t ws_opcode; /**< websocket opcode */ - uint8_t size; /**< size of the message */ - uint8_t mask[4]; /**< mask bytes */ -} jerry_websocket_receive_header_t; - -/** - * Convert a 6-bit value to a Base64 character. - * - * @return Base64 character - */ -static uint8_t -jerry_to_base64_character (uint8_t value) /**< 6-bit value */ -{ - if (value < 26) - { - return (uint8_t) (value + 'A'); - } - - if (value < 52) - { - return (uint8_t) (value - 26 + 'a'); - } - - if (value < 62) - { - return (uint8_t) (value - 52 + '0'); - } - - if (value == 62) - { - return (uint8_t) '+'; - } - - return (uint8_t) '/'; -} /* jerry_to_base64_character */ - -/** - * Encode a byte sequence into Base64 string. - */ -static void -jerry_to_base64 (const uint8_t *source_p, /**< source data */ - uint8_t *destination_p, /**< destination buffer */ - size_t length) /**< length of source, must be divisible by 3 */ -{ - while (length >= 3) - { - uint8_t value = (source_p[0] >> 2); - destination_p[0] = jerry_to_base64_character (value); - - value = (uint8_t) (((source_p[0] << 4) | (source_p[1] >> 4)) & 0x3f); - destination_p[1] = jerry_to_base64_character (value); - - value = (uint8_t) (((source_p[1] << 2) | (source_p[2] >> 6)) & 0x3f); - destination_p[2] = jerry_to_base64_character (value); - - value = (uint8_t) (source_p[2] & 0x3f); - destination_p[3] = jerry_to_base64_character (value); - - source_p += 3; - destination_p += 4; - length -= 3; - } -} /* jerry_to_base64 */ - -/** - * Process WebSocket handshake. - * - * @return true - if the handshake was completed successfully - * false - otherwise - */ -static bool -jerry_process_handshake (uint8_t *request_buffer_p) /**< temporary buffer */ -{ - size_t request_buffer_size = 1024; - uint8_t *request_end_p = request_buffer_p; - - /* Buffer request text until the double newlines are received. */ - while (true) - { - jerry_debugger_transport_receive_context_t context; - if (!jerry_debugger_transport_receive (&context)) - { - JERRY_ASSERT (!jerry_debugger_transport_is_connected ()); - return false; - } - - if (context.message_p == NULL) - { - jerry_debugger_transport_sleep (); - continue; - } - - size_t length = request_buffer_size - 1u - (size_t) (request_end_p - request_buffer_p); - - if (length < context.message_length) - { - JERRY_ERROR_MSG ("Handshake buffer too small.\n"); - return false; - } - - /* Both stream and datagram packets are supported. */ - memcpy (request_end_p, context.message_p, context.message_length); - - jerry_debugger_transport_receive_completed (&context); - - request_end_p += (size_t) context.message_length; - *request_end_p = 0; - - if (request_end_p > request_buffer_p + 4 - && memcmp (request_end_p - 4, "\r\n\r\n", 4) == 0) - { - break; - } - } - - /* Check protocol. */ - const char *text_p = "GET /jerry-debugger"; - size_t text_len = strlen (text_p); - - if ((size_t) (request_end_p - request_buffer_p) < text_len - || memcmp (request_buffer_p, text_p, text_len) != 0) - { - JERRY_ERROR_MSG ("Invalid handshake format.\n"); - return false; - } - - uint8_t *websocket_key_p = request_buffer_p + text_len; - - text_p = "Sec-WebSocket-Key:"; - text_len = strlen (text_p); - - while (true) - { - if ((size_t) (request_end_p - websocket_key_p) < text_len) - { - JERRY_ERROR_MSG ("Sec-WebSocket-Key not found.\n"); - return false; - } - - if (websocket_key_p[0] == 'S' - && websocket_key_p[-1] == '\n' - && websocket_key_p[-2] == '\r' - && memcmp (websocket_key_p, text_p, text_len) == 0) - { - websocket_key_p += text_len; - break; - } - - websocket_key_p++; - } - - /* String terminated by double newlines. */ - - while (*websocket_key_p == ' ') - { - websocket_key_p++; - } - - uint8_t *websocket_key_end_p = websocket_key_p; - - while (*websocket_key_end_p > ' ') - { - websocket_key_end_p++; - } - - /* Since the request_buffer_p is not needed anymore it can - * be reused for storing the SHA-1 key and Base64 string. */ - - const size_t sha1_length = 20; - - jerry_debugger_compute_sha1 (websocket_key_p, - (size_t) (websocket_key_end_p - websocket_key_p), - (const uint8_t *) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", - 36, - request_buffer_p); - - /* The SHA-1 key is 20 bytes long but jerry_to_base64 expects - * a length divisible by 3 so an extra 0 is appended at the end. */ - request_buffer_p[sha1_length] = 0; - - jerry_to_base64 (request_buffer_p, request_buffer_p + sha1_length + 1, sha1_length + 1); - - /* Last value must be replaced by equal sign. */ - - text_p = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "; - - if (!jerry_debugger_transport_send ((const uint8_t *) text_p, strlen (text_p)) - || !jerry_debugger_transport_send (request_buffer_p + sha1_length + 1, 27)) - { - return false; - } - - text_p = "=\r\n\r\n"; - return jerry_debugger_transport_send ((const uint8_t *) text_p, strlen (text_p)); -} /* jerry_process_handshake */ - -/** - * Close a tcp connection. - */ -static void -jerry_debugger_ws_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */ -{ - JERRY_ASSERT (jerry_debugger_transport_is_connected ()); - - jerry_debugger_transport_free ((void *) header_p, sizeof (jerry_debugger_transport_header_t)); -} /* jerry_debugger_ws_close */ - -/** - * Send data over a websocket connection. - * - * @return true - if the data has been sent successfully - * false - otherwise - */ -static bool -jerry_debugger_ws_send (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */ - uint8_t *message_p, /**< message to be sent */ - size_t message_length) /**< message length in bytes */ -{ - JERRY_ASSERT (message_length <= JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX); - - message_p[-2] = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME; - message_p[-1] = (uint8_t) message_length; - - return header_p->next_p->send (header_p->next_p, message_p - 2, message_length + 2); -} /* jerry_debugger_ws_send */ - -/** - * Receive data from a websocket connection. - */ -static bool -jerry_debugger_ws_receive (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */ - jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */ -{ - if (!header_p->next_p->receive (header_p->next_p, receive_context_p)) - { - return false; - } - - if (receive_context_p->message_p == NULL) - { - return true; - } - - size_t message_total_length = receive_context_p->message_total_length; - - if (message_total_length == 0) - { - /* Byte stream. */ - if (receive_context_p->message_length < sizeof (jerry_websocket_receive_header_t)) - { - receive_context_p->message_p = NULL; - return true; - } - } - else - { - /* Datagram packet. */ - JERRY_ASSERT (receive_context_p->message_length >= sizeof (jerry_websocket_receive_header_t)); - } - - uint8_t *message_p = receive_context_p->message_p; - - if ((message_p[0] & ~JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_FIN_BIT - || (message_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX - || !(message_p[1] & JERRY_DEBUGGER_WEBSOCKET_MASK_BIT)) - { - JERRY_ERROR_MSG ("Unsupported Websocket message.\n"); - jerry_debugger_transport_close (); - return false; - } - - if ((message_p[0] & JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME) - { - JERRY_ERROR_MSG ("Unsupported Websocket opcode.\n"); - jerry_debugger_transport_close (); - return false; - } - - size_t message_length = (size_t) (message_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK); - - if (message_total_length == 0) - { - size_t new_total_length = message_length + sizeof (jerry_websocket_receive_header_t); - - /* Byte stream. */ - if (receive_context_p->message_length < new_total_length) - { - receive_context_p->message_p = NULL; - return true; - } - - receive_context_p->message_total_length = new_total_length; - } - else - { - /* Datagram packet. */ - JERRY_ASSERT (receive_context_p->message_length == (message_length + sizeof (jerry_websocket_receive_header_t))); - } - - message_p += sizeof (jerry_websocket_receive_header_t); - - receive_context_p->message_p = message_p; - receive_context_p->message_length = message_length; - - /* Unmask data bytes. */ - const uint8_t *mask_p = message_p - JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE; - const uint8_t *mask_end_p = message_p; - const uint8_t *message_end_p = message_p + message_length; - - while (message_p < message_end_p) - { - /* Invert certain bits with xor operation. */ - *message_p = *message_p ^ *mask_p; - - message_p++; - mask_p++; - - if (JERRY_UNLIKELY (mask_p >= mask_end_p)) - { - mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE; - } - } - - return true; -} /* jerry_debugger_ws_receive */ - -/** - * Initialize the websocket transportation layer. - * - * @return true - if the connection succeeded - * false - otherwise - */ -bool -jerry_debugger_ws_create (void) -{ - bool is_handshake_ok = false; - - const size_t buffer_size = 1024; - uint8_t *request_buffer_p = (uint8_t *) jerry_debugger_transport_malloc (buffer_size); - - if (!request_buffer_p) - { - return false; - } - - is_handshake_ok = jerry_process_handshake (request_buffer_p); - - jerry_debugger_transport_free ((void *) request_buffer_p, buffer_size); - - if (!is_handshake_ok && jerry_debugger_transport_is_connected ()) - { - return false; - } - - const size_t interface_size = sizeof (jerry_debugger_transport_header_t); - jerry_debugger_transport_header_t *header_p; - header_p = (jerry_debugger_transport_header_t *) jerry_debugger_transport_malloc (interface_size); - - if (!header_p) - { - return false; - } - - header_p->close = jerry_debugger_ws_close; - header_p->send = jerry_debugger_ws_send; - header_p->receive = jerry_debugger_ws_receive; - - jerry_debugger_transport_add (header_p, - JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE, - JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX, - JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE + JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE, - JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX); - - return true; -} /* jerry_debugger_ws_create */ - -#endif /* JERRY_DEBUGGER */ |