aboutsummaryrefslogtreecommitdiff
path: root/jerry-core/debugger/debugger-ws.c
diff options
context:
space:
mode:
Diffstat (limited to 'jerry-core/debugger/debugger-ws.c')
-rw-r--r--jerry-core/debugger/debugger-ws.c451
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 */