diff --git a/jerry-core/api/jerry-debugger.c b/jerry-core/api/jerry-debugger.c index 627727b5dc..5a85f54873 100644 --- a/jerry-core/api/jerry-debugger.c +++ b/jerry-core/api/jerry-debugger.c @@ -93,16 +93,44 @@ jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint) /**< enable/d * Debugger server initialization. Must be called after jerry_init. */ void -jerry_debugger_init (uint16_t port) /**< server port number */ +jerry_debugger_init (jerry_debugger_transport_t *transport_p) /**< transport */ { #ifdef JERRY_DEBUGGER - JERRY_CONTEXT (debugger_port) = port; + JERRY_CONTEXT (debugger_transport_p) = transport_p; + JERRY_ASSERT (JERRY_CONTEXT (debugger_transport_p) != NULL); + JERRY_ASSERT (JERRY_CONTEXT (debugger_transport_p)->accept_connection != NULL); + JERRY_ASSERT (JERRY_CONTEXT (debugger_transport_p)->close_connection != NULL); + JERRY_ASSERT (JERRY_CONTEXT (debugger_transport_p)->send != NULL); + JERRY_ASSERT (JERRY_CONTEXT (debugger_transport_p)->receive != NULL); jerry_debugger_accept_connection (); #else /* !JERRY_DEBUGGER */ - JERRY_UNUSED (port); + JERRY_UNUSED (transport_p); #endif /* JERRY_DEBUGGER */ } /* jerry_debugger_init */ +/** + * Debugger transport transmission sizes, each transport will need to set these. + */ +void +jerry_debugger_set_transmit_sizes (size_t send_header_size, /**< transport send header size */ + size_t max_send_size, /**< transport max send size */ + size_t receive_header_size, /**< transport receive header size */ + size_t max_receive_size) /**< transport max receive size */ +{ +#ifdef JERRY_DEBUGGER + JERRY_CONTEXT (debugger_send_header_size) = (uint8_t) send_header_size; + JERRY_CONTEXT (debugger_max_send_size) = (uint8_t) max_send_size; + JERRY_CONTEXT (debugger_receive_header_size) = (uint8_t) receive_header_size; + JERRY_CONTEXT (debugger_max_receive_size) = (uint8_t) max_receive_size; +#else /* !JERRY_DEBUGGER */ + JERRY_UNUSED (send_header_size); + JERRY_UNUSED (max_send_size); + JERRY_UNUSED (receive_header_size); + JERRY_UNUSED (max_receive_size); +#endif /* JERRY_DEBUGGER */ +} /* jerry_debugger_set_transmit_sizes */ + + /** * Sets whether the engine should wait and run a source. * diff --git a/jerry-core/debugger/debugger-ws.h b/jerry-core/debugger/debugger-ws.h index 3a7c97c807..b2698dcd91 100644 --- a/jerry-core/debugger/debugger-ws.h +++ b/jerry-core/debugger/debugger-ws.h @@ -38,18 +38,12 @@ typedef struct /** * Byte data for evaluating expressions and receiving client source. */ -typedef struct +typedef struct jerry_debugger_uint8_data_t { uint32_t uint8_size; /**< total size of the client source */ uint32_t uint8_offset; /**< current offset in the client source */ } jerry_debugger_uint8_data_t; -bool jerry_debugger_accept_connection (void); -void jerry_debugger_close_connection (void); - -bool jerry_debugger_send (size_t data_size); -bool jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p); - void jerry_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len, const uint8_t *input2, size_t input2_len, uint8_t output[20]); diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c index 24330d026d..4c9f24f87f 100644 --- a/jerry-core/debugger/debugger.c +++ b/jerry-core/debugger/debugger.c @@ -1068,4 +1068,166 @@ jerry_debugger_send_exception_string (void) return result; } /* jerry_debugger_send_exception_string */ +/** + * Initialize the debugger connection. + * + * @return true - if the connection succeeded + * false - otherwise + */ +bool +jerry_debugger_accept_connection (void) +{ + uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer) + JERRY_CONTEXT (debugger_send_header_size); + JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p; + + uint8_t max_send_size = (uint8_t) (JERRY_DEBUGGER_MAX_BUFFER_SIZE - + JERRY_CONTEXT (debugger_send_header_size)); + if (max_send_size <= JERRY_CONTEXT (debugger_max_send_size)) + { + JERRY_CONTEXT (debugger_max_send_size) = max_send_size; + } + + uint8_t max_receive_size = (uint8_t) (JERRY_DEBUGGER_MAX_BUFFER_SIZE - + JERRY_CONTEXT (debugger_receive_header_size)); + if (max_receive_size <= JERRY_CONTEXT (debugger_max_send_size)) + { + JERRY_CONTEXT (debugger_max_receive_size) = max_receive_size; + } + + if (!JERRY_CONTEXT (debugger_transport_p)->accept_connection (JERRY_CONTEXT (debugger_transport_p))) + { + return false; + } + + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED); + + if (!jerry_debugger_send_configuration (max_receive_size)) + { + return false; + } + + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); + JERRY_CONTEXT (debugger_stop_context) = NULL; + return true; +} /* jerry_debugger_accept_connection */ + +/** + * Close the connection to the client. + */ +void +jerry_debugger_close_connection (void) +{ + JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); + JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE; + + JERRY_CONTEXT (debugger_transport_p)->close_connection (JERRY_CONTEXT (debugger_transport_p)); + jerry_debugger_free_unreferenced_byte_code (); +} /* jerry_debugger_close_connection */ + +/** + * Send message to the client side + * + * @return true - if the data was sent successfully to the debugger client, + * false - otherwise + */ +bool +jerry_debugger_send (size_t data_size) /**< data size */ +{ + JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); + JERRY_ASSERT (data_size <= JERRY_CONTEXT (debugger_max_send_size)); + + if (!JERRY_CONTEXT (debugger_transport_p)->send (JERRY_CONTEXT (debugger_transport_p), + JERRY_CONTEXT (debugger_send_buffer), + data_size)) + { + jerry_debugger_close_connection (); + return false; + } + + return true; +} /* jerry_debugger_send */ + +/** + * Receive message from the client. + * + * Note: + * If the function returns with true, the value of + * JERRY_DEBUGGER_VM_STOP flag should be ignored. + * + * @return true - if execution should be resumed, + * false - otherwise + */ +bool +jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] data received from client */ +{ + JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); + JERRY_ASSERT (message_data_p != NULL ? !!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE) + : !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE)); + + JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; + + bool resume_exec = false; + uint8_t expected_message_type = 0; + size_t message_size; + + while (true) + { + uint32_t offset = JERRY_CONTEXT (debugger_receive_buffer_offset); + bool success = JERRY_CONTEXT (debugger_transport_p)->receive (JERRY_CONTEXT (debugger_transport_p), + JERRY_CONTEXT (debugger_receive_buffer), + &message_size, + &offset); + + if (!success) + { + jerry_debugger_close_connection (); + return true; + } + + if (offset < JERRY_CONTEXT (debugger_receive_header_size)) + { + if (expected_message_type != 0) + { + continue; + } + + return resume_exec; + } + + uint32_t message_total_size = (uint32_t) (message_size + + JERRY_CONTEXT (debugger_receive_header_size)); + + if (offset < message_total_size) + { + if (expected_message_type != 0) + { + continue; + } + + return resume_exec; + } + + /* The jerry_debugger_process_message function is inlined + * so passing these arguments is essentially free. */ + if (!jerry_debugger_process_message (JERRY_CONTEXT (debugger_receive_buffer) + + JERRY_CONTEXT (debugger_receive_header_size), + (uint32_t) message_size, + &resume_exec, + &expected_message_type, + (jerry_debugger_uint8_data_t**) message_data_p)) + { + return true; + } + + if (message_total_size < offset) + { + memmove (JERRY_CONTEXT (debugger_receive_buffer), + JERRY_CONTEXT (debugger_receive_buffer) + message_total_size, + offset - message_total_size); + } + + JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) (offset - message_total_size); + } +} /* jerry_debugger_receive */ + #endif /* JERRY_DEBUGGER */ diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h index 94d701423d..f55cbc4ce8 100644 --- a/jerry-core/debugger/debugger.h +++ b/jerry-core/debugger/debugger.h @@ -107,6 +107,12 @@ typedef enum JERRY_DEBUGGER_CONTEXT_RESET_MODE = 1u << 10, /**< debugger and engine reinitialization mode */ } jerry_debugger_flags_t; +/** + * Waiting for data from the client. + */ +#define JERRY_DEBUGGER_RECEIVE_DATA_MODE \ + (JERRY_DEBUGGER_BREAKPOINT_MODE | JERRY_DEBUGGER_CLIENT_SOURCE_MODE) + /** * Set debugger flags. */ @@ -415,6 +421,11 @@ bool jerry_debugger_send_parse_function (uint32_t line, uint32_t column); void jerry_debugger_send_memstats (void); bool jerry_debugger_send_exception_string (void); +bool jerry_debugger_accept_connection (void); +void jerry_debugger_close_connection (void); +bool jerry_debugger_send (size_t data_size); +bool jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p); + #endif /* JERRY_DEBUGGER */ #endif /* !DEBUGGER_H */ diff --git a/jerry-core/include/jerryscript-debugger.h b/jerry-core/include/jerryscript-debugger.h index c6e73a79a7..dd6b2f7f10 100644 --- a/jerry-core/include/jerryscript-debugger.h +++ b/jerry-core/include/jerryscript-debugger.h @@ -53,7 +53,13 @@ typedef jerry_value_t (*jerry_debugger_wait_for_source_callback_t) (const jerry_ /** * Engine debugger functions. */ -void jerry_debugger_init (uint16_t port); +typedef struct jerry_debugger_transport_t jerry_debugger_transport_t; + +void jerry_debugger_init (jerry_debugger_transport_t *transport_p); +void jerry_debugger_set_transmit_sizes (size_t send_header_size, + size_t max_send_size, + size_t receive_header_size, + size_t max_receive_size); bool jerry_debugger_is_connected (void); void jerry_debugger_stop (void); void jerry_debugger_continue (void); diff --git a/jerry-core/include/jerryscript-port.h b/jerry-core/include/jerryscript-port.h index 8fc8ba8822..17a536526b 100644 --- a/jerry-core/include/jerryscript-port.h +++ b/jerry-core/include/jerryscript-port.h @@ -150,6 +150,30 @@ double jerry_port_get_current_time (void); */ struct jerry_instance_t *jerry_port_get_current_instance (void); +/* + * Debugger Port API + */ + +/* forward declaration */ +struct jerry_debugger_uint8_data_t; + +/** + * Transport APIs, different transport will define + * the real implementation of these APIs + */ +struct jerry_debugger_transport_t +{ + bool (*accept_connection) (struct jerry_debugger_transport_t *transport_p); + void (*close_connection) (struct jerry_debugger_transport_t *transport_p); + bool (*send) (struct jerry_debugger_transport_t *transport_p, + uint8_t *message_data_p, + size_t data_size); + bool (*receive) (struct jerry_debugger_transport_t *transport_p, + uint8_t *message_data_p, + size_t *data_size, + uint32_t *buffer_offset); +}; + /** * Makes the process sleep for a given time. * diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 917c5e9c19..23e81e656f 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -117,11 +117,12 @@ typedef struct jmem_cpointer_t debugger_byte_code_free_tail; /**< tail of byte code free linked list */ uint32_t debugger_flags; /**< debugger flags */ uint16_t debugger_receive_buffer_offset; /**< receive buffer offset */ - uint16_t debugger_port; /**< debugger socket communication port */ uint8_t debugger_message_delay; /**< call receive message when reaches zero */ + uint8_t debugger_send_header_size; /**< header size reserved when sending */ + uint8_t debugger_receive_header_size; /**< header size reserved when receiving */ uint8_t debugger_max_send_size; /**< maximum amount of data that can be written */ uint8_t debugger_max_receive_size; /**< maximum amount of data that can be received */ - int debugger_connection; /**< holds the file descriptor of the socket communication */ + jerry_debugger_transport_t *debugger_transport_p; /**< holds the pointer to the debugger transport */ #endif /* JERRY_DEBUGGER */ #ifdef JERRY_ENABLE_LINE_INFO diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index a6814a2886..e1ac1abbd1 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -592,7 +592,7 @@ main (int argc, jerry_init (flags); if (start_debug_server) { - jerry_debugger_init (debug_port); + jerry_debugger_init (jerry_port_default_init_socket_transport (debug_port)); } register_js_function ("assert", jerryx_handler_assert); @@ -710,7 +710,7 @@ main (int argc, jerry_cleanup (); jerry_init (flags); - jerry_debugger_init (debug_port); + jerry_debugger_init (jerry_port_default_init_socket_transport (debug_port)); register_js_function ("assert", jerryx_handler_assert); register_js_function ("gc", jerryx_handler_gc); diff --git a/jerry-core/debugger/debugger-ws.c b/jerry-port/default/default-debugger-transport.c similarity index 60% rename from jerry-core/debugger/debugger-ws.c rename to jerry-port/default/default-debugger-transport.c index b9d9975af4..63d6c3a128 100644 --- a/jerry-core/debugger/debugger-ws.c +++ b/jerry-port/default/default-debugger-transport.c @@ -13,15 +13,16 @@ * limitations under the License. */ -#include "debugger.h" -#include "jcontext.h" #include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "jmem.h" #ifdef JERRY_DEBUGGER #include #include #include +#include #include /* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */ @@ -46,6 +47,11 @@ */ #define JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK 0x7fu +/** + * Maximum number of bytes transmitted or received. + */ +#define JERRY_DEBUGGER_MAX_BUFFER_SIZE 128 + /** * Size of websocket header size. */ @@ -89,16 +95,19 @@ typedef struct uint8_t mask[4]; /**< mask bytes */ } jerry_debugger_receive_header_t; +static uint16_t debugger_port; /**< debugger socket communication port */ +static int fd; /**< holds the file descriptor of the socket communication */ + +void jerry_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len, + const uint8_t *input2, size_t input2_len, + uint8_t output[20]); + /** * Close the socket connection to the client. */ static void jerry_debugger_close_connection_tcp (bool log_error) /**< log error */ { - JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); - - JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE; - if (log_error) { JERRY_ERROR_MSG ("Error: %s\n", strerror (errno)); @@ -106,10 +115,13 @@ jerry_debugger_close_connection_tcp (bool log_error) /**< log error */ JERRY_DEBUG_MSG ("Debugger client connection closed.\n"); - close (JERRY_CONTEXT (debugger_connection)); - JERRY_CONTEXT (debugger_connection) = -1; + if (fd != -1) + { + close (fd); + fd = -1; + } - jerry_debugger_free_unreferenced_byte_code (); + JERRY_DEBUG_MSG ("Debugger client connection closed.\n"); } /* jerry_debugger_close_connection_tcp */ /** @@ -122,11 +134,9 @@ static bool jerry_debugger_send_tcp (const uint8_t *data_p, /**< data pointer */ size_t data_size) /**< data size */ { - JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); - do { - ssize_t sent_bytes = send (JERRY_CONTEXT (debugger_connection), data_p, data_size, 0); + ssize_t sent_bytes = send (fd, data_p, data_size, 0); if (sent_bytes < 0) { @@ -330,39 +340,28 @@ jerry_process_handshake (int client_socket, /**< client socket */ } /* jerry_process_handshake */ /** - * Initialize the socket connection. + * Default implementation of debugger accept_connection api. This implementation + * uses a socket API which is not yet supported by jerry-libc so the standard + * libc is used instead. + * + * Note: + * This function is only available if the port implementation library is + * compiled with the JERRY_DEBUGGER macro. * * @return true - if the connection succeeded * false - otherwise */ -bool -jerry_debugger_accept_connection (void) +static bool +jerry_debugger_accept_connection_ws (struct jerry_debugger_transport_t *transport_p) /**< transport object */ { + JERRY_UNUSED (transport_p); + int server_socket; struct sockaddr_in addr; socklen_t sin_size = sizeof (struct sockaddr_in); - uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer) + JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE; - JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p; - - uint8_t max_send_size = (JERRY_DEBUGGER_MAX_BUFFER_SIZE - JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE); - if (max_send_size > JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX) - { - max_send_size = JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX; - } - JERRY_CONTEXT (debugger_max_send_size) = max_send_size; - - uint8_t receive_header_size = (JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE + JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE); - uint8_t max_receive_size = (uint8_t) (JERRY_DEBUGGER_MAX_BUFFER_SIZE - receive_header_size); - - if (max_receive_size > JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX) - { - max_receive_size = JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX; - } - JERRY_CONTEXT (debugger_max_receive_size) = max_receive_size; - addr.sin_family = AF_INET; - addr.sin_port = htons (JERRY_CONTEXT (debugger_port)); + addr.sin_port = htons (debugger_port); addr.sin_addr.s_addr = INADDR_ANY; if ((server_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1) @@ -396,9 +395,9 @@ jerry_debugger_accept_connection (void) JERRY_DEBUG_MSG ("Waiting for client connection\n"); - JERRY_CONTEXT (debugger_connection) = accept (server_socket, (struct sockaddr *)&addr, &sin_size); + fd = accept (server_socket, (struct sockaddr *)&addr, &sin_size); - if (JERRY_CONTEXT (debugger_connection) == -1) + if (fd == -1) { close (server_socket); JERRY_ERROR_MSG ("Error: %s\n", strerror (errno)); @@ -407,205 +406,201 @@ jerry_debugger_accept_connection (void) close (server_socket); - JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED); - bool is_handshake_ok = false; JMEM_DEFINE_LOCAL_ARRAY (request_buffer_p, 1024, uint8_t); - is_handshake_ok = jerry_process_handshake (JERRY_CONTEXT (debugger_connection), - request_buffer_p); + is_handshake_ok = jerry_process_handshake (fd, request_buffer_p); JMEM_FINALIZE_LOCAL_ARRAY (request_buffer_p); if (!is_handshake_ok) { - jerry_debugger_close_connection (); - return false; - } - - if (!jerry_debugger_send_configuration (max_receive_size)) - { + jerry_debugger_close_connection_tcp (false); return false; } /* Set non-blocking mode. */ - int socket_flags = fcntl (JERRY_CONTEXT (debugger_connection), F_GETFL, 0); + int socket_flags = fcntl (fd, F_GETFL, 0); if (socket_flags < 0) { + JERRY_ERROR_MSG ("socket_flags error: %s\n", strerror (errno)); jerry_debugger_close_connection_tcp (true); return false; } - if (fcntl (JERRY_CONTEXT (debugger_connection), F_SETFL, socket_flags | O_NONBLOCK) == -1) + if (fcntl (fd, F_SETFL, socket_flags | O_NONBLOCK) == -1) { + JERRY_ERROR_MSG ("nonblock error: %s\n", strerror (errno)); jerry_debugger_close_connection_tcp (true); return false; } JERRY_DEBUG_MSG ("Connected from: %s\n", inet_ntoa (addr.sin_addr)); - JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); - JERRY_CONTEXT (debugger_stop_context) = NULL; - return true; -} /* jerry_debugger_accept_connection */ +} /* jerry_debugger_accept_connection_ws */ /** + * Default implementation of debugger close_connection api. * Close the socket connection to the client. */ -inline void __attr_always_inline___ -jerry_debugger_close_connection (void) +static inline void __attr_always_inline___ +jerry_debugger_close_connection_ws (struct jerry_debugger_transport_t *transport_p) /**< transport object */ { + JERRY_UNUSED (transport_p); + jerry_debugger_close_connection_tcp (false); -} /* jerry_debugger_close_connection */ +} /* jerry_debugger_close_connection_ws */ /** - * Send message to the client side + * Default implementation of debugger send api. + * Send message to the client side. + * + * Note: + * This function is only available if the port implementation library is + * compiled with the JERRY_DEBUGGER macro. * - * @return true - if the data was sent successfully to the debugger client, + * @return true - if the data was sent successfully to the client side * false - otherwise */ -bool -jerry_debugger_send (size_t data_size) /**< data size */ +static bool +jerry_debugger_send_ws (struct jerry_debugger_transport_t *transport_p, /**< transport object */ + uint8_t *message_data_p, /**< send data pointer */ + size_t data_size) /**< send data size */ { - JERRY_ASSERT (data_size <= JERRY_CONTEXT (debugger_max_send_size)); + JERRY_UNUSED (transport_p); - uint8_t *header_p = JERRY_CONTEXT (debugger_send_buffer); + uint8_t *header_p = message_data_p; header_p[0] = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME; header_p[1] = (uint8_t) data_size; return jerry_debugger_send_tcp (header_p, data_size + JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE); -} /* jerry_debugger_send */ +} /* jerry_debugger_send_ws */ /** - * Receive message from the client. + * Default implementation of debugger receive api. + * Receive message from the client side. * - * Note: - * If the function returns with true, the value of - * JERRY_DEBUGGER_VM_STOP flag should be ignored. + * This function is only available if the port implementation library is + * compiled with the JERRY_DEBUGGER macro. * - * @return true - if execution should be resumed, + * @return true - if the data was received successfully from the client side, * false - otherwise */ -bool -jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] data received from client */ +static bool +jerry_debugger_receive_ws (struct jerry_debugger_transport_t *transport_p, /**< transport object */ + uint8_t *message_data_p, /**< received data pointer */ + size_t *data_size, /**< [out] received data size */ + uint32_t *data_offset) /**< [in/out] data buffer offset */ { - JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); - JERRY_ASSERT (JERRY_CONTEXT (debugger_max_receive_size) <= JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX); - - JERRY_ASSERT (message_data_p != NULL ? !!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE) - : !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE)); + JERRY_UNUSED (transport_p); - JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; + uint8_t *recv_buffer_p = message_data_p; + uint32_t offset = *data_offset; - uint8_t *recv_buffer_p = JERRY_CONTEXT (debugger_receive_buffer); - bool resume_exec = false; - uint8_t expected_message_type = 0; + ssize_t byte_recv = recv (fd, + message_data_p + offset, + JERRY_DEBUGGER_MAX_BUFFER_SIZE - offset, + 0); - while (true) + if (byte_recv < 0) { - uint32_t offset = JERRY_CONTEXT (debugger_receive_buffer_offset); - - ssize_t byte_recv = recv (JERRY_CONTEXT (debugger_connection), - recv_buffer_p + offset, - JERRY_DEBUGGER_MAX_BUFFER_SIZE - offset, - 0); - - if (byte_recv < 0) + if (errno != EWOULDBLOCK) { - if (errno != EWOULDBLOCK) - { - jerry_debugger_close_connection_tcp (true); - return true; - } - - byte_recv = 0; + JERRY_ERROR_MSG ("recv error: %s\n", strerror (errno)); + jerry_debugger_close_connection_tcp (true); + return false; } - offset += (uint32_t) byte_recv; - JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) offset; - - if (offset < sizeof (jerry_debugger_receive_header_t)) - { - if (expected_message_type != 0) - { - continue; - } - - return resume_exec; - } + byte_recv = 0; + } - if ((recv_buffer_p[0] & ~JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_FIN_BIT - || (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRY_CONTEXT (debugger_max_receive_size) - || !(recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_MASK_BIT)) - { - JERRY_ERROR_MSG ("Unsupported Websocket message.\n"); - jerry_debugger_close_connection (); - return true; - } + offset += (uint32_t) byte_recv; + *data_offset = offset; - if ((recv_buffer_p[0] & JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME) - { - JERRY_ERROR_MSG ("Unsupported Websocket opcode.\n"); - jerry_debugger_close_connection (); - return true; - } + if (offset < sizeof (jerry_debugger_receive_header_t)) + { + return true; + } - uint32_t message_size = (uint32_t) (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK); - uint32_t message_total_size = (uint32_t) (message_size + sizeof (jerry_debugger_receive_header_t)); + uint8_t receive_header_size = JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE + JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE; + uint8_t max_receive_size = (uint8_t) (JERRY_DEBUGGER_MAX_BUFFER_SIZE - receive_header_size); + if ((recv_buffer_p[0] & ~JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_FIN_BIT + || (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) > max_receive_size + || !(recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_MASK_BIT)) + { + JERRY_ERROR_MSG ("Unsupported Websocket message.\n"); + return false; + } - if (offset < message_total_size) - { - if (expected_message_type != 0) - { - continue; - } + if ((recv_buffer_p[0] & JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME) + { + JERRY_ERROR_MSG ("Unsupported Websocket opcode.\n"); + return false; + } - return resume_exec; - } + uint32_t message_size = (uint32_t) (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK); + uint32_t message_total_size = (uint32_t) (message_size + sizeof (jerry_debugger_receive_header_t)); - /* Unmask data bytes. */ - uint8_t *data_p = recv_buffer_p + sizeof (jerry_debugger_receive_header_t); - const uint8_t *mask_p = data_p - JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE; - const uint8_t *mask_end_p = data_p; - const uint8_t *data_end_p = data_p + message_size; + if (offset < message_total_size) + { + return true; + } - while (data_p < data_end_p) - { - /* Invert certain bits with xor operation. */ - *data_p = *data_p ^ *mask_p; + /* Unmask data bytes. */ + uint8_t *data_p = recv_buffer_p + sizeof (jerry_debugger_receive_header_t); + const uint8_t *mask_p = data_p - JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE; + const uint8_t *mask_end_p = data_p; + const uint8_t *data_end_p = data_p + message_size; - data_p++; - mask_p++; + while (data_p < data_end_p) + { + /* Invert certain bits with xor operation. */ + *data_p = *data_p ^ *mask_p; - if (mask_p >= mask_end_p) - { - mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE; - } - } + data_p++; + mask_p++; - /* The jerry_debugger_process_message function is inlined - * so passing these arguments is essentially free. */ - if (!jerry_debugger_process_message (recv_buffer_p + sizeof (jerry_debugger_receive_header_t), - message_size, - &resume_exec, - &expected_message_type, - message_data_p)) + if (mask_p >= mask_end_p) { - return true; + mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE; } + } - if (message_total_size < offset) - { - memmove (recv_buffer_p, - recv_buffer_p + message_total_size, - offset - message_total_size); - } + *data_size = (size_t) message_size; - JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) (offset - message_total_size); - } -} /* jerry_debugger_receive */ + return true; +} /* jerry_debugger_receive_ws */ + +static struct jerry_debugger_transport_t socket_transport = +{ + .accept_connection = jerry_debugger_accept_connection_ws, + .close_connection = jerry_debugger_close_connection_ws, + .send = jerry_debugger_send_ws, + .receive = jerry_debugger_receive_ws, +}; + +#endif /* JERRY_DEBUGGER */ +/** + * Create and return the socket transport on the provided port for the debugger + * + * @return the transport created + */ +struct jerry_debugger_transport_t * +jerry_port_default_init_socket_transport (uint16_t tcp_port) /**< server port number */ +{ +#ifdef JERRY_DEBUGGER + debugger_port = tcp_port; + jerry_debugger_set_transmit_sizes (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 &socket_transport; +#else /* !JERRY_DEBUGGER */ + JERRY_UNUSED (tcp_port); + return NULL; #endif /* JERRY_DEBUGGER */ +} /* jerry_port_default_init_socket_transport */ diff --git a/jerry-port/default/include/jerryscript-port-default.h b/jerry-port/default/include/jerryscript-port-default.h index 6d66cb9d73..59701c49c7 100644 --- a/jerry-port/default/include/jerryscript-port-default.h +++ b/jerry-port/default/include/jerryscript-port-default.h @@ -39,6 +39,12 @@ void jerry_port_default_set_log_level (jerry_log_level_t level); void jerry_port_default_set_instance (jerry_instance_t *instance_p); +/** + * The default transport layer that uses TCP socket + * other transports can be added like usb, bluetooth + */ +struct jerry_debugger_transport_t *jerry_port_default_init_socket_transport (uint16_t tcp_port); + /** * @} */ diff --git a/targets/nuttx-stm32f4/jerry_main.c b/targets/nuttx-stm32f4/jerry_main.c index c1086c07d5..152a401687 100644 --- a/targets/nuttx-stm32f4/jerry_main.c +++ b/targets/nuttx-stm32f4/jerry_main.c @@ -292,6 +292,17 @@ register_js_function (const char *name_p, /**< name of the function */ */ static jerry_log_level_t jerry_log_level = JERRY_LOG_LEVEL_ERROR; +/** + * Dummy function to return the transport. + * + * @return NULL + */ +jerry_debugger_transport_t * +jerry_port_init_socket_transport (uint16_t tcp_port) /**< server port number */ +{ + return NULL; +} /* jerry_port_init_socket_transport */ + /** * Main program. * @@ -380,7 +391,7 @@ int jerry_main (int argc, char *argv[]) if (start_debug_server) { - jerry_debugger_init (debug_port); + jerry_debugger_init (jerry_port_init_socket_transport (debug_port)); } register_js_function ("assert", jerryx_handler_assert); diff --git a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c index b771304101..b3c8bdab48 100644 --- a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c +++ b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c @@ -270,6 +270,16 @@ register_js_function (const char *name_p, /**< name of the function */ */ static jerry_log_level_t jerry_log_level = JERRY_LOG_LEVEL_ERROR; +/** + * Dummy function to return the transport. + * + * @return NULL + */ +jerry_debugger_transport_t * +jerry_port_init_socket_transport (uint16_t tcp_port) /**< server port number */ +{ + return NULL; +} /* jerry_port_init_socket_transport */ /** * JerryScript command main @@ -356,7 +366,7 @@ jerry_cmd_main (int argc, char *argv[]) if (start_debug_server) { - jerry_debugger_init (debug_port); + jerry_debugger_init (jerry_port_init_socket_transport (debug_port)); } register_js_function ("assert", jerryx_handler_assert);