1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation 2425bb815Sopenharmony_ci * 3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License. 5425bb815Sopenharmony_ci * You may obtain a copy of the License at 6425bb815Sopenharmony_ci * 7425bb815Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8425bb815Sopenharmony_ci * 9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS 11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and 13425bb815Sopenharmony_ci * limitations under the License. 14425bb815Sopenharmony_ci */ 15425bb815Sopenharmony_ci 16425bb815Sopenharmony_ci#include "debugger-sha1.h" 17425bb815Sopenharmony_ci#include "jerryscript-ext/debugger.h" 18425bb815Sopenharmony_ci#include "jext-common.h" 19425bb815Sopenharmony_ci 20425bb815Sopenharmony_ci#if defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) 21425bb815Sopenharmony_ci 22425bb815Sopenharmony_ci/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */ 23425bb815Sopenharmony_ci 24425bb815Sopenharmony_ci/** 25425bb815Sopenharmony_ci * Last fragment of a Websocket package. 26425bb815Sopenharmony_ci */ 27425bb815Sopenharmony_ci#define JERRYX_DEBUGGER_WEBSOCKET_FIN_BIT 0x80 28425bb815Sopenharmony_ci 29425bb815Sopenharmony_ci/** 30425bb815Sopenharmony_ci * Masking-key is available. 31425bb815Sopenharmony_ci */ 32425bb815Sopenharmony_ci#define JERRYX_DEBUGGER_WEBSOCKET_MASK_BIT 0x80 33425bb815Sopenharmony_ci 34425bb815Sopenharmony_ci/** 35425bb815Sopenharmony_ci * Opcode type mask. 36425bb815Sopenharmony_ci */ 37425bb815Sopenharmony_ci#define JERRYX_DEBUGGER_WEBSOCKET_OPCODE_MASK 0x0fu 38425bb815Sopenharmony_ci 39425bb815Sopenharmony_ci/** 40425bb815Sopenharmony_ci * Packet length mask. 41425bb815Sopenharmony_ci */ 42425bb815Sopenharmony_ci#define JERRYX_DEBUGGER_WEBSOCKET_LENGTH_MASK 0x7fu 43425bb815Sopenharmony_ci 44425bb815Sopenharmony_ci/** 45425bb815Sopenharmony_ci * Size of websocket header size. 46425bb815Sopenharmony_ci */ 47425bb815Sopenharmony_ci#define JERRYX_DEBUGGER_WEBSOCKET_HEADER_SIZE 2 48425bb815Sopenharmony_ci 49425bb815Sopenharmony_ci/** 50425bb815Sopenharmony_ci * Payload mask size in bytes of a websocket package. 51425bb815Sopenharmony_ci */ 52425bb815Sopenharmony_ci#define JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE 4 53425bb815Sopenharmony_ci 54425bb815Sopenharmony_ci/** 55425bb815Sopenharmony_ci * Maximum message size with 1 byte size field. 56425bb815Sopenharmony_ci */ 57425bb815Sopenharmony_ci#define JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX 125 58425bb815Sopenharmony_ci 59425bb815Sopenharmony_ci/** 60425bb815Sopenharmony_ci * WebSocket opcode types. 61425bb815Sopenharmony_ci */ 62425bb815Sopenharmony_citypedef enum 63425bb815Sopenharmony_ci{ 64425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_TEXT_FRAME = 1, /**< text frame */ 65425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_BINARY_FRAME = 2, /**< binary frame */ 66425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_CLOSE_CONNECTION = 8, /**< close connection */ 67425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_PING = 9, /**< ping (keep alive) frame */ 68425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_PONG = 10, /**< reply to ping frame */ 69425bb815Sopenharmony_ci} jerryx_websocket_opcode_type_t; 70425bb815Sopenharmony_ci 71425bb815Sopenharmony_ci/** 72425bb815Sopenharmony_ci * Header for incoming packets. 73425bb815Sopenharmony_ci */ 74425bb815Sopenharmony_citypedef struct 75425bb815Sopenharmony_ci{ 76425bb815Sopenharmony_ci uint8_t ws_opcode; /**< websocket opcode */ 77425bb815Sopenharmony_ci uint8_t size; /**< size of the message */ 78425bb815Sopenharmony_ci uint8_t mask[4]; /**< mask bytes */ 79425bb815Sopenharmony_ci} jerryx_websocket_receive_header_t; 80425bb815Sopenharmony_ci 81425bb815Sopenharmony_ci/** 82425bb815Sopenharmony_ci * Convert a 6-bit value to a Base64 character. 83425bb815Sopenharmony_ci * 84425bb815Sopenharmony_ci * @return Base64 character 85425bb815Sopenharmony_ci */ 86425bb815Sopenharmony_cistatic uint8_t 87425bb815Sopenharmony_cijerryx_to_base64_character (uint8_t value) /**< 6-bit value */ 88425bb815Sopenharmony_ci{ 89425bb815Sopenharmony_ci if (value < 26) 90425bb815Sopenharmony_ci { 91425bb815Sopenharmony_ci return (uint8_t) (value + 'A'); 92425bb815Sopenharmony_ci } 93425bb815Sopenharmony_ci 94425bb815Sopenharmony_ci if (value < 52) 95425bb815Sopenharmony_ci { 96425bb815Sopenharmony_ci return (uint8_t) (value - 26 + 'a'); 97425bb815Sopenharmony_ci } 98425bb815Sopenharmony_ci 99425bb815Sopenharmony_ci if (value < 62) 100425bb815Sopenharmony_ci { 101425bb815Sopenharmony_ci return (uint8_t) (value - 52 + '0'); 102425bb815Sopenharmony_ci } 103425bb815Sopenharmony_ci 104425bb815Sopenharmony_ci if (value == 62) 105425bb815Sopenharmony_ci { 106425bb815Sopenharmony_ci return (uint8_t) '+'; 107425bb815Sopenharmony_ci } 108425bb815Sopenharmony_ci 109425bb815Sopenharmony_ci return (uint8_t) '/'; 110425bb815Sopenharmony_ci} /* jerryx_to_base64_character */ 111425bb815Sopenharmony_ci 112425bb815Sopenharmony_ci/** 113425bb815Sopenharmony_ci * Encode a byte sequence into Base64 string. 114425bb815Sopenharmony_ci */ 115425bb815Sopenharmony_cistatic void 116425bb815Sopenharmony_cijerryx_to_base64 (const uint8_t *source_p, /**< source data */ 117425bb815Sopenharmony_ci uint8_t *destination_p, /**< destination buffer */ 118425bb815Sopenharmony_ci size_t length) /**< length of source, must be divisible by 3 */ 119425bb815Sopenharmony_ci{ 120425bb815Sopenharmony_ci while (length >= 3) 121425bb815Sopenharmony_ci { 122425bb815Sopenharmony_ci uint8_t value = (source_p[0] >> 2); 123425bb815Sopenharmony_ci destination_p[0] = jerryx_to_base64_character (value); 124425bb815Sopenharmony_ci 125425bb815Sopenharmony_ci value = (uint8_t) (((source_p[0] << 4) | (source_p[1] >> 4)) & 0x3f); 126425bb815Sopenharmony_ci destination_p[1] = jerryx_to_base64_character (value); 127425bb815Sopenharmony_ci 128425bb815Sopenharmony_ci value = (uint8_t) (((source_p[1] << 2) | (source_p[2] >> 6)) & 0x3f); 129425bb815Sopenharmony_ci destination_p[2] = jerryx_to_base64_character (value); 130425bb815Sopenharmony_ci 131425bb815Sopenharmony_ci value = (uint8_t) (source_p[2] & 0x3f); 132425bb815Sopenharmony_ci destination_p[3] = jerryx_to_base64_character (value); 133425bb815Sopenharmony_ci 134425bb815Sopenharmony_ci source_p += 3; 135425bb815Sopenharmony_ci destination_p += 4; 136425bb815Sopenharmony_ci length -= 3; 137425bb815Sopenharmony_ci } 138425bb815Sopenharmony_ci} /* jerryx_to_base64 */ 139425bb815Sopenharmony_ci 140425bb815Sopenharmony_ci/** 141425bb815Sopenharmony_ci * Process WebSocket handshake. 142425bb815Sopenharmony_ci * 143425bb815Sopenharmony_ci * @return true - if the handshake was completed successfully 144425bb815Sopenharmony_ci * false - otherwise 145425bb815Sopenharmony_ci */ 146425bb815Sopenharmony_cistatic bool 147425bb815Sopenharmony_cijerryx_process_handshake (uint8_t *request_buffer_p) /**< temporary buffer */ 148425bb815Sopenharmony_ci{ 149425bb815Sopenharmony_ci size_t request_buffer_size = 1024; 150425bb815Sopenharmony_ci uint8_t *request_end_p = request_buffer_p; 151425bb815Sopenharmony_ci 152425bb815Sopenharmony_ci /* Buffer request text until the double newlines are received. */ 153425bb815Sopenharmony_ci while (true) 154425bb815Sopenharmony_ci { 155425bb815Sopenharmony_ci jerry_debugger_transport_receive_context_t context; 156425bb815Sopenharmony_ci if (!jerry_debugger_transport_receive (&context)) 157425bb815Sopenharmony_ci { 158425bb815Sopenharmony_ci JERRYX_ASSERT (!jerry_debugger_transport_is_connected ()); 159425bb815Sopenharmony_ci return false; 160425bb815Sopenharmony_ci } 161425bb815Sopenharmony_ci 162425bb815Sopenharmony_ci if (context.message_p == NULL) 163425bb815Sopenharmony_ci { 164425bb815Sopenharmony_ci jerry_debugger_transport_sleep (); 165425bb815Sopenharmony_ci continue; 166425bb815Sopenharmony_ci } 167425bb815Sopenharmony_ci 168425bb815Sopenharmony_ci size_t length = request_buffer_size - 1u - (size_t) (request_end_p - request_buffer_p); 169425bb815Sopenharmony_ci 170425bb815Sopenharmony_ci if (length < context.message_length) 171425bb815Sopenharmony_ci { 172425bb815Sopenharmony_ci JERRYX_ERROR_MSG ("Handshake buffer too small.\n"); 173425bb815Sopenharmony_ci return false; 174425bb815Sopenharmony_ci } 175425bb815Sopenharmony_ci 176425bb815Sopenharmony_ci /* Both stream and datagram packets are supported. */ 177425bb815Sopenharmony_ci memcpy (request_end_p, context.message_p, context.message_length); 178425bb815Sopenharmony_ci 179425bb815Sopenharmony_ci jerry_debugger_transport_receive_completed (&context); 180425bb815Sopenharmony_ci 181425bb815Sopenharmony_ci request_end_p += (size_t) context.message_length; 182425bb815Sopenharmony_ci *request_end_p = 0; 183425bb815Sopenharmony_ci 184425bb815Sopenharmony_ci if (request_end_p > request_buffer_p + 4 185425bb815Sopenharmony_ci && memcmp (request_end_p - 4, "\r\n\r\n", 4) == 0) 186425bb815Sopenharmony_ci { 187425bb815Sopenharmony_ci break; 188425bb815Sopenharmony_ci } 189425bb815Sopenharmony_ci } 190425bb815Sopenharmony_ci 191425bb815Sopenharmony_ci /* Check protocol. */ 192425bb815Sopenharmony_ci const char get_text[] = "GET /jerry-debugger"; 193425bb815Sopenharmony_ci size_t text_len = sizeof (get_text) - 1; 194425bb815Sopenharmony_ci 195425bb815Sopenharmony_ci if ((size_t) (request_end_p - request_buffer_p) < text_len 196425bb815Sopenharmony_ci || memcmp (request_buffer_p, get_text, text_len) != 0) 197425bb815Sopenharmony_ci { 198425bb815Sopenharmony_ci JERRYX_ERROR_MSG ("Invalid handshake format.\n"); 199425bb815Sopenharmony_ci return false; 200425bb815Sopenharmony_ci } 201425bb815Sopenharmony_ci 202425bb815Sopenharmony_ci uint8_t *websocket_key_p = request_buffer_p + text_len; 203425bb815Sopenharmony_ci 204425bb815Sopenharmony_ci const char key_text[] = "Sec-WebSocket-Key:"; 205425bb815Sopenharmony_ci text_len = sizeof (key_text) - 1; 206425bb815Sopenharmony_ci 207425bb815Sopenharmony_ci while (true) 208425bb815Sopenharmony_ci { 209425bb815Sopenharmony_ci if ((size_t) (request_end_p - websocket_key_p) < text_len) 210425bb815Sopenharmony_ci { 211425bb815Sopenharmony_ci JERRYX_ERROR_MSG ("Sec-WebSocket-Key not found.\n"); 212425bb815Sopenharmony_ci return false; 213425bb815Sopenharmony_ci } 214425bb815Sopenharmony_ci 215425bb815Sopenharmony_ci if (websocket_key_p[0] == 'S' 216425bb815Sopenharmony_ci && websocket_key_p[-1] == '\n' 217425bb815Sopenharmony_ci && websocket_key_p[-2] == '\r' 218425bb815Sopenharmony_ci && memcmp (websocket_key_p, key_text, text_len) == 0) 219425bb815Sopenharmony_ci { 220425bb815Sopenharmony_ci websocket_key_p += text_len; 221425bb815Sopenharmony_ci break; 222425bb815Sopenharmony_ci } 223425bb815Sopenharmony_ci 224425bb815Sopenharmony_ci websocket_key_p++; 225425bb815Sopenharmony_ci } 226425bb815Sopenharmony_ci 227425bb815Sopenharmony_ci /* String terminated by double newlines. */ 228425bb815Sopenharmony_ci 229425bb815Sopenharmony_ci while (*websocket_key_p == ' ') 230425bb815Sopenharmony_ci { 231425bb815Sopenharmony_ci websocket_key_p++; 232425bb815Sopenharmony_ci } 233425bb815Sopenharmony_ci 234425bb815Sopenharmony_ci uint8_t *websocket_key_end_p = websocket_key_p; 235425bb815Sopenharmony_ci 236425bb815Sopenharmony_ci while (*websocket_key_end_p > ' ') 237425bb815Sopenharmony_ci { 238425bb815Sopenharmony_ci websocket_key_end_p++; 239425bb815Sopenharmony_ci } 240425bb815Sopenharmony_ci 241425bb815Sopenharmony_ci /* Since the request_buffer_p is not needed anymore it can 242425bb815Sopenharmony_ci * be reused for storing the SHA-1 key and Base64 string. */ 243425bb815Sopenharmony_ci 244425bb815Sopenharmony_ci const size_t sha1_length = 20; 245425bb815Sopenharmony_ci 246425bb815Sopenharmony_ci jerryx_debugger_compute_sha1 (websocket_key_p, 247425bb815Sopenharmony_ci (size_t) (websocket_key_end_p - websocket_key_p), 248425bb815Sopenharmony_ci (const uint8_t *) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 249425bb815Sopenharmony_ci 36, 250425bb815Sopenharmony_ci request_buffer_p); 251425bb815Sopenharmony_ci 252425bb815Sopenharmony_ci /* The SHA-1 key is 20 bytes long but jerryx_to_base64 expects 253425bb815Sopenharmony_ci * a length divisible by 3 so an extra 0 is appended at the end. */ 254425bb815Sopenharmony_ci request_buffer_p[sha1_length] = 0; 255425bb815Sopenharmony_ci 256425bb815Sopenharmony_ci jerryx_to_base64 (request_buffer_p, request_buffer_p + sha1_length + 1, sha1_length + 1); 257425bb815Sopenharmony_ci 258425bb815Sopenharmony_ci /* Last value must be replaced by equal sign. */ 259425bb815Sopenharmony_ci 260425bb815Sopenharmony_ci const uint8_t response_prefix[] = 261425bb815Sopenharmony_ci "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "; 262425bb815Sopenharmony_ci 263425bb815Sopenharmony_ci if (!jerry_debugger_transport_send (response_prefix, sizeof (response_prefix) - 1) 264425bb815Sopenharmony_ci || !jerry_debugger_transport_send (request_buffer_p + sha1_length + 1, 27)) 265425bb815Sopenharmony_ci { 266425bb815Sopenharmony_ci return false; 267425bb815Sopenharmony_ci } 268425bb815Sopenharmony_ci 269425bb815Sopenharmony_ci const uint8_t response_suffix[] = "=\r\n\r\n"; 270425bb815Sopenharmony_ci return jerry_debugger_transport_send (response_suffix, sizeof (response_suffix) - 1); 271425bb815Sopenharmony_ci} /* jerryx_process_handshake */ 272425bb815Sopenharmony_ci 273425bb815Sopenharmony_ci/** 274425bb815Sopenharmony_ci * Close a tcp connection. 275425bb815Sopenharmony_ci */ 276425bb815Sopenharmony_cistatic void 277425bb815Sopenharmony_cijerryx_debugger_ws_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */ 278425bb815Sopenharmony_ci{ 279425bb815Sopenharmony_ci JERRYX_ASSERT (!jerry_debugger_transport_is_connected ()); 280425bb815Sopenharmony_ci 281425bb815Sopenharmony_ci jerry_heap_free ((void *) header_p, sizeof (jerry_debugger_transport_header_t)); 282425bb815Sopenharmony_ci} /* jerryx_debugger_ws_close */ 283425bb815Sopenharmony_ci 284425bb815Sopenharmony_ci/** 285425bb815Sopenharmony_ci * Send data over a websocket connection. 286425bb815Sopenharmony_ci * 287425bb815Sopenharmony_ci * @return true - if the data has been sent successfully 288425bb815Sopenharmony_ci * false - otherwise 289425bb815Sopenharmony_ci */ 290425bb815Sopenharmony_cistatic bool 291425bb815Sopenharmony_cijerryx_debugger_ws_send (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */ 292425bb815Sopenharmony_ci uint8_t *message_p, /**< message to be sent */ 293425bb815Sopenharmony_ci size_t message_length) /**< message length in bytes */ 294425bb815Sopenharmony_ci{ 295425bb815Sopenharmony_ci JERRYX_ASSERT (message_length <= JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX); 296425bb815Sopenharmony_ci 297425bb815Sopenharmony_ci message_p[-2] = JERRYX_DEBUGGER_WEBSOCKET_FIN_BIT | JERRYX_DEBUGGER_WEBSOCKET_BINARY_FRAME; 298425bb815Sopenharmony_ci message_p[-1] = (uint8_t) message_length; 299425bb815Sopenharmony_ci 300425bb815Sopenharmony_ci return header_p->next_p->send (header_p->next_p, message_p - 2, message_length + 2); 301425bb815Sopenharmony_ci} /* jerryx_debugger_ws_send */ 302425bb815Sopenharmony_ci 303425bb815Sopenharmony_ci/** 304425bb815Sopenharmony_ci * Receive data from a websocket connection. 305425bb815Sopenharmony_ci */ 306425bb815Sopenharmony_cistatic bool 307425bb815Sopenharmony_cijerryx_debugger_ws_receive (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */ 308425bb815Sopenharmony_ci jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */ 309425bb815Sopenharmony_ci{ 310425bb815Sopenharmony_ci if (!header_p->next_p->receive (header_p->next_p, receive_context_p)) 311425bb815Sopenharmony_ci { 312425bb815Sopenharmony_ci return false; 313425bb815Sopenharmony_ci } 314425bb815Sopenharmony_ci 315425bb815Sopenharmony_ci if (receive_context_p->message_p == NULL) 316425bb815Sopenharmony_ci { 317425bb815Sopenharmony_ci return true; 318425bb815Sopenharmony_ci } 319425bb815Sopenharmony_ci 320425bb815Sopenharmony_ci size_t message_total_length = receive_context_p->message_total_length; 321425bb815Sopenharmony_ci 322425bb815Sopenharmony_ci if (message_total_length == 0) 323425bb815Sopenharmony_ci { 324425bb815Sopenharmony_ci /* Byte stream. */ 325425bb815Sopenharmony_ci if (receive_context_p->message_length < sizeof (jerryx_websocket_receive_header_t)) 326425bb815Sopenharmony_ci { 327425bb815Sopenharmony_ci receive_context_p->message_p = NULL; 328425bb815Sopenharmony_ci return true; 329425bb815Sopenharmony_ci } 330425bb815Sopenharmony_ci } 331425bb815Sopenharmony_ci else 332425bb815Sopenharmony_ci { 333425bb815Sopenharmony_ci /* Datagram packet. */ 334425bb815Sopenharmony_ci JERRYX_ASSERT (receive_context_p->message_length >= sizeof (jerryx_websocket_receive_header_t)); 335425bb815Sopenharmony_ci } 336425bb815Sopenharmony_ci 337425bb815Sopenharmony_ci uint8_t *message_p = receive_context_p->message_p; 338425bb815Sopenharmony_ci 339425bb815Sopenharmony_ci if ((message_p[0] & ~JERRYX_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRYX_DEBUGGER_WEBSOCKET_FIN_BIT 340425bb815Sopenharmony_ci || (message_p[1] & JERRYX_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX 341425bb815Sopenharmony_ci || !(message_p[1] & JERRYX_DEBUGGER_WEBSOCKET_MASK_BIT)) 342425bb815Sopenharmony_ci { 343425bb815Sopenharmony_ci JERRYX_ERROR_MSG ("Unsupported Websocket message.\n"); 344425bb815Sopenharmony_ci jerry_debugger_transport_close (); 345425bb815Sopenharmony_ci return false; 346425bb815Sopenharmony_ci } 347425bb815Sopenharmony_ci 348425bb815Sopenharmony_ci if ((message_p[0] & JERRYX_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRYX_DEBUGGER_WEBSOCKET_BINARY_FRAME) 349425bb815Sopenharmony_ci { 350425bb815Sopenharmony_ci JERRYX_ERROR_MSG ("Unsupported Websocket opcode.\n"); 351425bb815Sopenharmony_ci jerry_debugger_transport_close (); 352425bb815Sopenharmony_ci return false; 353425bb815Sopenharmony_ci } 354425bb815Sopenharmony_ci 355425bb815Sopenharmony_ci size_t message_length = (size_t) (message_p[1] & JERRYX_DEBUGGER_WEBSOCKET_LENGTH_MASK); 356425bb815Sopenharmony_ci 357425bb815Sopenharmony_ci if (message_total_length == 0) 358425bb815Sopenharmony_ci { 359425bb815Sopenharmony_ci size_t new_total_length = message_length + sizeof (jerryx_websocket_receive_header_t); 360425bb815Sopenharmony_ci 361425bb815Sopenharmony_ci /* Byte stream. */ 362425bb815Sopenharmony_ci if (receive_context_p->message_length < new_total_length) 363425bb815Sopenharmony_ci { 364425bb815Sopenharmony_ci receive_context_p->message_p = NULL; 365425bb815Sopenharmony_ci return true; 366425bb815Sopenharmony_ci } 367425bb815Sopenharmony_ci 368425bb815Sopenharmony_ci receive_context_p->message_total_length = new_total_length; 369425bb815Sopenharmony_ci } 370425bb815Sopenharmony_ci else 371425bb815Sopenharmony_ci { 372425bb815Sopenharmony_ci /* Datagram packet. */ 373425bb815Sopenharmony_ci JERRYX_ASSERT (receive_context_p->message_length == (message_length + sizeof (jerryx_websocket_receive_header_t))); 374425bb815Sopenharmony_ci } 375425bb815Sopenharmony_ci 376425bb815Sopenharmony_ci message_p += sizeof (jerryx_websocket_receive_header_t); 377425bb815Sopenharmony_ci 378425bb815Sopenharmony_ci receive_context_p->message_p = message_p; 379425bb815Sopenharmony_ci receive_context_p->message_length = message_length; 380425bb815Sopenharmony_ci 381425bb815Sopenharmony_ci /* Unmask data bytes. */ 382425bb815Sopenharmony_ci const uint8_t *mask_p = message_p - JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE; 383425bb815Sopenharmony_ci const uint8_t *mask_end_p = message_p; 384425bb815Sopenharmony_ci const uint8_t *message_end_p = message_p + message_length; 385425bb815Sopenharmony_ci 386425bb815Sopenharmony_ci while (message_p < message_end_p) 387425bb815Sopenharmony_ci { 388425bb815Sopenharmony_ci /* Invert certain bits with xor operation. */ 389425bb815Sopenharmony_ci *message_p = *message_p ^ *mask_p; 390425bb815Sopenharmony_ci 391425bb815Sopenharmony_ci message_p++; 392425bb815Sopenharmony_ci mask_p++; 393425bb815Sopenharmony_ci 394425bb815Sopenharmony_ci if (JERRY_UNLIKELY (mask_p >= mask_end_p)) 395425bb815Sopenharmony_ci { 396425bb815Sopenharmony_ci mask_p -= JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE; 397425bb815Sopenharmony_ci } 398425bb815Sopenharmony_ci } 399425bb815Sopenharmony_ci 400425bb815Sopenharmony_ci return true; 401425bb815Sopenharmony_ci} /* jerryx_debugger_ws_receive */ 402425bb815Sopenharmony_ci 403425bb815Sopenharmony_ci/** 404425bb815Sopenharmony_ci * Initialize the websocket transportation layer. 405425bb815Sopenharmony_ci * 406425bb815Sopenharmony_ci * @return true - if the connection succeeded 407425bb815Sopenharmony_ci * false - otherwise 408425bb815Sopenharmony_ci */ 409425bb815Sopenharmony_cibool 410425bb815Sopenharmony_cijerryx_debugger_ws_create (void) 411425bb815Sopenharmony_ci{ 412425bb815Sopenharmony_ci bool is_handshake_ok = false; 413425bb815Sopenharmony_ci 414425bb815Sopenharmony_ci const size_t buffer_size = 1024; 415425bb815Sopenharmony_ci uint8_t *request_buffer_p = (uint8_t *) jerry_heap_alloc (buffer_size); 416425bb815Sopenharmony_ci 417425bb815Sopenharmony_ci if (!request_buffer_p) 418425bb815Sopenharmony_ci { 419425bb815Sopenharmony_ci return false; 420425bb815Sopenharmony_ci } 421425bb815Sopenharmony_ci 422425bb815Sopenharmony_ci is_handshake_ok = jerryx_process_handshake (request_buffer_p); 423425bb815Sopenharmony_ci 424425bb815Sopenharmony_ci jerry_heap_free ((void *) request_buffer_p, buffer_size); 425425bb815Sopenharmony_ci 426425bb815Sopenharmony_ci if (!is_handshake_ok && jerry_debugger_transport_is_connected ()) 427425bb815Sopenharmony_ci { 428425bb815Sopenharmony_ci return false; 429425bb815Sopenharmony_ci } 430425bb815Sopenharmony_ci 431425bb815Sopenharmony_ci const size_t interface_size = sizeof (jerry_debugger_transport_header_t); 432425bb815Sopenharmony_ci jerry_debugger_transport_header_t *header_p; 433425bb815Sopenharmony_ci header_p = (jerry_debugger_transport_header_t *) jerry_heap_alloc (interface_size); 434425bb815Sopenharmony_ci 435425bb815Sopenharmony_ci if (!header_p) 436425bb815Sopenharmony_ci { 437425bb815Sopenharmony_ci return false; 438425bb815Sopenharmony_ci } 439425bb815Sopenharmony_ci 440425bb815Sopenharmony_ci header_p->close = jerryx_debugger_ws_close; 441425bb815Sopenharmony_ci header_p->send = jerryx_debugger_ws_send; 442425bb815Sopenharmony_ci header_p->receive = jerryx_debugger_ws_receive; 443425bb815Sopenharmony_ci 444425bb815Sopenharmony_ci jerry_debugger_transport_add (header_p, 445425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_HEADER_SIZE, 446425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX, 447425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_HEADER_SIZE + JERRYX_DEBUGGER_WEBSOCKET_MASK_SIZE, 448425bb815Sopenharmony_ci JERRYX_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX); 449425bb815Sopenharmony_ci 450425bb815Sopenharmony_ci return true; 451425bb815Sopenharmony_ci} /* jerryx_debugger_ws_create */ 452425bb815Sopenharmony_ci 453425bb815Sopenharmony_ci#else /* !(defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1)) */ 454425bb815Sopenharmony_ci 455425bb815Sopenharmony_ci/** 456425bb815Sopenharmony_ci * Dummy function when debugger is disabled. 457425bb815Sopenharmony_ci * 458425bb815Sopenharmony_ci * @return false 459425bb815Sopenharmony_ci */ 460425bb815Sopenharmony_cibool 461425bb815Sopenharmony_cijerryx_debugger_ws_create (void) 462425bb815Sopenharmony_ci{ 463425bb815Sopenharmony_ci return false; 464425bb815Sopenharmony_ci} /* jerryx_debugger_ws_create */ 465425bb815Sopenharmony_ci 466425bb815Sopenharmony_ci#endif /* defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) */ 467