aboutsummaryrefslogtreecommitdiff
path: root/jerry-core
diff options
context:
space:
mode:
authorZoltan Herczeg <zherczeg.u-szeged@partner.samsung.com>2018-07-12 18:21:08 +0200
committeryichoi <duddlf.choi@samsung.com>2018-07-13 01:21:08 +0900
commit857ba99694c9a48c34f6e35af69a70e3eed407b1 (patch)
tree6367cb2e4a0a4f3124090d27e798258b37cc8653 /jerry-core
parent43aae199ce60e0b8484ecb8f3deb1dc909dbfc12 (diff)
Rework JerryScript transport layer. (#2421)
Introducing jerryscript-debugger-transport.h interface, which allows chaining multiple protocols (e.g. tcp and websocket). JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
Diffstat (limited to 'jerry-core')
-rw-r--r--jerry-core/api/jerry-debugger-transport.c273
-rw-r--r--jerry-core/api/jerry-debugger.c14
-rw-r--r--jerry-core/api/jerry.c3
-rw-r--r--jerry-core/debugger/debugger-tcp.c237
-rw-r--r--jerry-core/debugger/debugger-tcp.h27
-rw-r--r--jerry-core/debugger/debugger-ws.c448
-rw-r--r--jerry-core/debugger/debugger-ws.h30
-rw-r--r--jerry-core/debugger/debugger.c143
-rw-r--r--jerry-core/debugger/debugger.h26
-rw-r--r--jerry-core/include/jerryscript-debugger-transport.h107
-rw-r--r--jerry-core/include/jerryscript-debugger.h2
-rw-r--r--jerry-core/jcontext/jcontext.h12
-rw-r--r--jerry-core/parser/js/js-parser-internal.h10
-rw-r--r--jerry-core/parser/js/js-parser.c2
14 files changed, 947 insertions, 387 deletions
diff --git a/jerry-core/api/jerry-debugger-transport.c b/jerry-core/api/jerry-debugger-transport.c
new file mode 100644
index 00000000..d4ba0a3d
--- /dev/null
+++ b/jerry-core/api/jerry-debugger-transport.c
@@ -0,0 +1,273 @@
+/* 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.h"
+#include "jcontext.h"
+#include "jerryscript.h"
+
+#ifdef JERRY_DEBUGGER
+
+/**
+ * Minimum number of bytes transmitted or received.
+ */
+#define JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE 64
+
+/**
+ * Sleep time in milliseconds between each jerry_debugger_receive call
+ */
+#define JERRY_DEBUGGER_TRANSPORT_TIMEOUT 100
+
+/**
+ * Allocate memory for a connection.
+ *
+ * @return allocated memory on success
+ * NULL otherwise
+ */
+void *
+jerry_debugger_transport_malloc (size_t size) /**< size of the memory block */
+{
+ return jmem_heap_alloc_block_null_on_error (size);
+} /* jerry_debugger_transport_malloc */
+
+/**
+ * Free memory allocated for a connection.
+ */
+void
+jerry_debugger_transport_free (void *mem_p, /**< value returned by jerry_debugger_transport_malloc() */
+ size_t size) /**< same size passed to jerry_debugger_transport_malloc() */
+{
+ jmem_heap_free_block (mem_p, size);
+} /* jerry_debugger_transport_free */
+
+/**
+ * Add a new transport layer.
+ */
+void
+jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p, /**< transport implementation */
+ size_t send_message_header_size, /**< header bytes reserved for outgoing messages */
+ size_t max_send_message_size, /**< maximum number of bytes transmitted in a message */
+ size_t receive_message_header_size, /**< header bytes reserved for incoming messages */
+ size_t max_receive_message_size) /**< maximum number of bytes received in a message */
+{
+ JERRY_ASSERT (max_send_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE
+ && max_receive_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE);
+
+ header_p->next_p = JERRY_CONTEXT (debugger_transport_header_p);
+ JERRY_CONTEXT (debugger_transport_header_p) = header_p;
+
+ uint8_t *payload_p;
+ size_t max_send_size;
+ size_t max_receive_size;
+
+ if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
+ {
+ payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
+ max_send_size = JERRY_CONTEXT (debugger_max_send_size);
+ max_receive_size = JERRY_CONTEXT (debugger_max_receive_size);
+ }
+ else
+ {
+ JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED);
+ payload_p = JERRY_CONTEXT (debugger_send_buffer);
+ max_send_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
+ max_receive_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
+ }
+
+ JERRY_ASSERT (max_send_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + send_message_header_size);
+ JERRY_ASSERT (max_receive_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + receive_message_header_size);
+
+ JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p + send_message_header_size;
+
+ max_send_size = max_send_size - send_message_header_size;
+ max_receive_size = max_receive_size - receive_message_header_size;
+
+ if (max_send_size > max_send_message_size)
+ {
+ max_send_size = max_send_message_size;
+ }
+
+ if (max_receive_size > max_receive_message_size)
+ {
+ max_receive_size = max_receive_message_size;
+ }
+
+ JERRY_CONTEXT (debugger_max_send_size) = (uint8_t) max_send_size;
+ JERRY_CONTEXT (debugger_max_receive_size) = (uint8_t) max_receive_size;
+} /* jerry_debugger_transport_add */
+
+/**
+ * Starts the communication to the debugger client.
+ * Must be called after the connection is successfully established.
+ */
+void
+jerry_debugger_transport_start (void)
+{
+ JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
+
+ if (jerry_debugger_send_configuration (JERRY_CONTEXT (debugger_max_receive_size)))
+ {
+ JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
+ JERRY_CONTEXT (debugger_stop_context) = NULL;
+ }
+} /* jerry_debugger_transport_start */
+
+/**
+ * Returns true if a debugger client is connected.
+ *
+ * @return true - a debugger client is connected,
+ * false - otherwise
+ */
+bool
+jerry_debugger_transport_is_connected (void)
+{
+ return (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0;
+} /* jerry_debugger_transport_is_connected */
+
+/**
+ * Notifies the debugger server that the connection is closed.
+ */
+void
+jerry_debugger_transport_close (void)
+{
+ if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED))
+ {
+ return;
+ }
+
+ jerry_debugger_transport_header_t *current_p = JERRY_CONTEXT (debugger_transport_header_p);
+
+ JERRY_ASSERT (current_p != NULL);
+
+ do
+ {
+ jerry_debugger_transport_header_t *next_p = current_p->next_p;
+
+ current_p->close (current_p);
+
+ current_p = next_p;
+ }
+ while (current_p != NULL);
+
+ JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE;
+
+ jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Debugger client connection closed.\n");
+
+ jerry_debugger_free_unreferenced_byte_code ();
+} /* jerry_debugger_transport_close */
+
+/**
+ * Send data over the current connection
+ *
+ * @return true - data sent successfully,
+ * false - connection closed
+ */
+bool
+jerry_debugger_transport_send (const uint8_t *message_p, /**< message to be sent */
+ size_t message_length) /**< message length in bytes */
+{
+ JERRY_ASSERT (jerry_debugger_transport_is_connected ());
+ JERRY_ASSERT (message_length > 0);
+
+ jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
+ uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
+ size_t max_send_size = JERRY_CONTEXT (debugger_max_send_size);
+
+ do
+ {
+ size_t fragment_length = (message_length <= max_send_size ? message_length
+ : max_send_size);
+
+ memcpy (payload_p, message_p, fragment_length);
+
+ if (!header_p->send (header_p, payload_p, fragment_length))
+ {
+ return false;
+ }
+
+ message_p += fragment_length;
+ message_length -= fragment_length;
+ }
+ while (message_length > 0);
+
+ return true;
+} /* jerry_debugger_transport_send */
+
+/**
+ * Receive data from the current connection
+ *
+ * Note:
+ * A message is received if message_start_p is not NULL
+ *
+ * @return true - function successfully completed,
+ * false - connection closed
+ */
+bool
+jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p) /**< [out] receive
+ * context */
+{
+ JERRY_ASSERT (jerry_debugger_transport_is_connected ());
+
+ context_p->buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
+ context_p->received_length = JERRY_CONTEXT (debugger_received_length);
+ context_p->message_p = NULL;
+ context_p->message_length = 0;
+ context_p->message_total_length = 0;
+
+ jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
+
+ return header_p->receive (header_p, context_p);
+} /* jerry_debugger_transport_receive */
+
+/**
+ * Clear the message buffer after the message is processed
+ */
+void
+jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p) /**< receive
+ * context */
+{
+ JERRY_ASSERT (context_p->message_p != NULL);
+ JERRY_ASSERT (context_p->buffer_p == JERRY_CONTEXT (debugger_receive_buffer));
+
+ size_t message_total_length = context_p->message_total_length;
+ size_t received_length = context_p->received_length;
+
+ JERRY_ASSERT (message_total_length <= received_length);
+
+ if (message_total_length == 0 || message_total_length == received_length)
+ {
+ /* All received data is processed. */
+ JERRY_CONTEXT (debugger_received_length) = 0;
+ return;
+ }
+
+ uint8_t *buffer_p = context_p->buffer_p;
+ received_length -= message_total_length;
+
+ memmove (buffer_p, buffer_p + message_total_length, received_length);
+
+ JERRY_CONTEXT (debugger_received_length) = (uint16_t) received_length;
+} /* jerry_debugger_transport_receive_completed */
+
+/**
+ * Suspend execution for a given time.
+ * Note: If the platform does not have nanosleep or usleep, this function does not sleep at all.
+ */
+void
+jerry_debugger_transport_sleep (void)
+{
+ jerry_port_sleep (JERRY_DEBUGGER_TRANSPORT_TIMEOUT);
+} /* jerry_debugger_transport_sleep */
+
+#endif /* JERRY_DEBUGGER */
diff --git a/jerry-core/api/jerry-debugger.c b/jerry-core/api/jerry-debugger.c
index 717ad840..22bca84d 100644
--- a/jerry-core/api/jerry-debugger.c
+++ b/jerry-core/api/jerry-debugger.c
@@ -16,6 +16,8 @@
#include "debugger.h"
#include "jcontext.h"
#include "jerryscript.h"
+#include "debugger-tcp.h"
+#include "debugger-ws.h"
/**
* Checks whether the debugger is connected.
@@ -96,8 +98,14 @@ void
jerry_debugger_init (uint16_t port) /**< server port number */
{
#ifdef JERRY_DEBUGGER
- JERRY_CONTEXT (debugger_port) = port;
- jerry_debugger_accept_connection ();
+ if (!jerry_debugger_tcp_create (port)
+ || !jerry_debugger_ws_create ())
+ {
+ jerry_debugger_transport_close ();
+ return;
+ }
+
+ jerry_debugger_transport_start ();
#else /* !JERRY_DEBUGGER */
JERRY_UNUSED (port);
#endif /* JERRY_DEBUGGER */
@@ -173,7 +181,7 @@ jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t
}
}
- jerry_debugger_sleep ();
+ jerry_debugger_transport_sleep ();
}
JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c
index 622705fb..6a8f9166 100644
--- a/jerry-core/api/jerry.c
+++ b/jerry-core/api/jerry.c
@@ -35,6 +35,7 @@
#include "ecma-typedarray-object.h"
#include "jcontext.h"
#include "jerryscript.h"
+#include "jerryscript-debugger-transport.h"
#include "jmem.h"
#include "js-parser.h"
#include "re-compiler.h"
@@ -199,7 +200,7 @@ jerry_cleanup (void)
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
}
#endif /* JERRY_DEBUGGER */
diff --git a/jerry-core/debugger/debugger-tcp.c b/jerry-core/debugger/debugger-tcp.c
new file mode 100644
index 00000000..7b80a530
--- /dev/null
+++ b/jerry-core/debugger/debugger-tcp.c
@@ -0,0 +1,237 @@
+/* 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-tcp.h"
+#include "jrt.h"
+
+#ifdef JERRY_DEBUGGER
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/**
+ * Implementation of transport over tcp/ip.
+ */
+typedef struct
+{
+ jerry_debugger_transport_header_t header; /**< transport header */
+ int tcp_socket; /**< tcp socket */
+} jerry_debugger_transport_tcp_t;
+
+/**
+ * Log tcp error message.
+ */
+static void
+jerry_debugger_tcp_log_error (void)
+{
+ JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
+} /* jerry_debugger_tcp_log_error */
+
+/**
+ * Close a tcp connection.
+ */
+static void
+jerry_debugger_tcp_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */
+{
+ JERRY_ASSERT (jerry_debugger_transport_is_connected ());
+
+ jerry_debugger_transport_tcp_t *tcp_p = (jerry_debugger_transport_tcp_t *) header_p;
+
+ JERRY_DEBUG_MSG ("TCP connection closed.\n");
+
+ close (tcp_p->tcp_socket);
+
+ jerry_debugger_transport_free ((void *) header_p, sizeof (jerry_debugger_transport_tcp_t));
+} /* jerry_debugger_tcp_close */
+
+/**
+ * Send data over a tcp connection.
+ *
+ * @return true - if the data has been sent successfully
+ * false - otherwise
+ */
+static bool
+jerry_debugger_tcp_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 (jerry_debugger_transport_is_connected ());
+
+ jerry_debugger_transport_tcp_t *tcp_p = (jerry_debugger_transport_tcp_t *) header_p;
+
+ do
+ {
+ ssize_t sent_bytes = send (tcp_p->tcp_socket, message_p, message_length, 0);
+
+ if (sent_bytes < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ {
+ continue;
+ }
+
+ jerry_debugger_tcp_log_error ();
+ jerry_debugger_transport_close ();
+ return false;
+ }
+
+ message_p += sent_bytes;
+ message_length -= (size_t) sent_bytes;
+ }
+ while (message_length > 0);
+
+ return true;
+} /* jerry_debugger_tcp_send */
+
+/**
+ * Receive data from a tcp connection.
+ */
+static bool
+jerry_debugger_tcp_receive (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
+ jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */
+{
+ jerry_debugger_transport_tcp_t *tcp_p = (jerry_debugger_transport_tcp_t *) header_p;
+
+ uint8_t *buffer_p = receive_context_p->buffer_p + receive_context_p->received_length;
+ size_t buffer_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE - receive_context_p->received_length;
+
+ ssize_t length = recv (tcp_p->tcp_socket, buffer_p, buffer_size, 0);
+
+ if (length < 0)
+ {
+ if (errno != EWOULDBLOCK)
+ {
+ jerry_debugger_tcp_log_error ();
+ jerry_debugger_transport_close ();
+ return false;
+ }
+ length = 0;
+ }
+
+ receive_context_p->received_length += (size_t) length;
+
+ if (receive_context_p->received_length > 0)
+ {
+ receive_context_p->message_p = receive_context_p->buffer_p;
+ receive_context_p->message_length = receive_context_p->received_length;
+ }
+
+ return true;
+} /* jerry_debugger_tcp_receive */
+
+/**
+ * Create a tcp connection.
+ *
+ * @return true if successful,
+ * false otherwise
+ */
+bool
+jerry_debugger_tcp_create (uint16_t port) /**< listening port */
+{
+ int server_socket;
+ struct sockaddr_in addr;
+ socklen_t sin_size = sizeof (struct sockaddr_in);
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if ((server_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ int opt_value = 1;
+
+ if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) == -1)
+ {
+ close (server_socket);
+ JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr)) == -1)
+ {
+ close (server_socket);
+ JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ if (listen (server_socket, 1) == -1)
+ {
+ close (server_socket);
+ JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ JERRY_DEBUG_MSG ("Waiting for client connection\n");
+
+ int tcp_socket = accept (server_socket, (struct sockaddr *)&addr, &sin_size);
+
+ close (server_socket);
+
+ if (tcp_socket == -1)
+ {
+ JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
+ return false;
+ }
+
+ /* Set non-blocking mode. */
+ int socket_flags = fcntl (tcp_socket, F_GETFL, 0);
+
+ if (socket_flags < 0)
+ {
+ close (tcp_socket);
+ return false;
+ }
+
+ if (fcntl (tcp_socket, F_SETFL, socket_flags | O_NONBLOCK) == -1)
+ {
+ close (tcp_socket);
+ return false;
+ }
+
+ JERRY_DEBUG_MSG ("Connected from: %s\n", inet_ntoa (addr.sin_addr));
+
+ size_t size = sizeof (jerry_debugger_transport_tcp_t);
+
+ jerry_debugger_transport_header_t *header_p;
+ header_p = (jerry_debugger_transport_header_t *) jerry_debugger_transport_malloc (size);
+
+ if (!header_p)
+ {
+ close (tcp_socket);
+ return false;
+ }
+
+ header_p->close = jerry_debugger_tcp_close;
+ header_p->send = jerry_debugger_tcp_send;
+ header_p->receive = jerry_debugger_tcp_receive;
+
+ ((jerry_debugger_transport_tcp_t *) header_p)->tcp_socket = tcp_socket;
+
+ jerry_debugger_transport_add (header_p,
+ 0,
+ JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE,
+ 0,
+ JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE);
+
+ return true;
+} /* jerry_debugger_tcp_create */
+
+#endif /* JERRY_DEBUGGER */
diff --git a/jerry-core/debugger/debugger-tcp.h b/jerry-core/debugger/debugger-tcp.h
new file mode 100644
index 00000000..a6d11aa8
--- /dev/null
+++ b/jerry-core/debugger/debugger-tcp.h
@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+#ifndef DEBUGGER_TCP_H
+#define DEBUGGER_TCP_H
+
+#include "jerryscript-debugger-transport.h"
+
+#ifdef JERRY_DEBUGGER
+
+bool jerry_debugger_tcp_create (uint16_t port);
+
+#endif /* JERRY_DEBUGGER */
+
+#endif /* !DEBUGGER_TCP_H */
diff --git a/jerry-core/debugger/debugger-ws.c b/jerry-core/debugger/debugger-ws.c
index 0f12a693..d980b9b7 100644
--- a/jerry-core/debugger/debugger-ws.c
+++ b/jerry-core/debugger/debugger-ws.c
@@ -13,17 +13,11 @@
* limitations under the License.
*/
-#include "debugger.h"
-#include "jcontext.h"
-#include "jerryscript-port.h"
+#include "debugger-ws.h"
+#include "jrt.h"
#ifdef JERRY_DEBUGGER
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
/**
@@ -62,12 +56,6 @@
#define JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX 125
/**
- * Waiting for data from the client.
- */
-#define JERRY_DEBUGGER_RECEIVE_DATA_MODE \
- (JERRY_DEBUGGER_BREAKPOINT_MODE | JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
-
-/**
* WebSocket opcode types.
*/
typedef enum
@@ -87,65 +75,7 @@ typedef struct
uint8_t ws_opcode; /**< websocket opcode */
uint8_t size; /**< size of the message */
uint8_t mask[4]; /**< mask bytes */
-} jerry_debugger_receive_header_t;
-
-/**
- * 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));
- }
-
- JERRY_DEBUG_MSG ("Debugger client connection closed.\n");
-
- close (JERRY_CONTEXT (debugger_connection));
- JERRY_CONTEXT (debugger_connection) = -1;
-
- jerry_debugger_free_unreferenced_byte_code ();
-} /* jerry_debugger_close_connection_tcp */
-
-/**
- * Send message to the client side.
- *
- * @return true - if the data was sent successfully to the client side
- * false - otherwise
- */
-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);
-
- if (sent_bytes < 0)
- {
- if (errno == EWOULDBLOCK)
- {
- continue;
- }
-
- jerry_debugger_close_connection_tcp (true);
- return false;
- }
-
- data_size -= (size_t) sent_bytes;
- data_p += sent_bytes;
- }
- while (data_size > 0);
-
- return true;
-} /* jerry_debugger_send_tcp */
+} jerry_websocket_receive_header_t;
/**
* Convert a 6-bit value to a Base64 character.
@@ -213,8 +143,7 @@ jerry_to_base64 (const uint8_t *source_p, /**< source data */
* false - otherwise
*/
static bool
-jerry_process_handshake (int client_socket, /**< client socket */
- uint8_t *request_buffer_p) /**< temporary buffer */
+jerry_process_handshake (uint8_t *request_buffer_p) /**< temporary buffer */
{
size_t request_buffer_size = 1024;
uint8_t *request_end_p = request_buffer_p;
@@ -222,23 +151,33 @@ jerry_process_handshake (int client_socket, /**< client socket */
/* Buffer request text until the double newlines are received. */
while (true)
{
- size_t length = request_buffer_size - 1u - (size_t) (request_end_p - request_buffer_p);
-
- if (length == 0)
+ jerry_debugger_transport_receive_context_t context;
+ if (!jerry_debugger_transport_receive (&context))
{
- JERRY_ERROR_MSG ("Handshake buffer too small.\n");
+ JERRY_ASSERT (!jerry_debugger_transport_is_connected ());
return false;
}
- ssize_t size = recv (client_socket, request_end_p, length, 0);
+ 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 (size < 0)
+ if (length < context.message_length)
{
- JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
+ JERRY_ERROR_MSG ("Handshake buffer too small.\n");
return false;
}
- request_end_p += (size_t) size;
+ /* 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
@@ -319,293 +258,194 @@ jerry_process_handshake (int client_socket, /**< client socket */
text_p = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
- if (!jerry_debugger_send_tcp ((const uint8_t *) text_p, strlen (text_p))
- || !jerry_debugger_send_tcp (request_buffer_p + sha1_length + 1, 27))
+ 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_send_tcp ((const uint8_t *) text_p, strlen (text_p));
+ return jerry_debugger_transport_send ((const uint8_t *) text_p, strlen (text_p));
} /* jerry_process_handshake */
/**
- * Initialize the socket connection.
- *
- * @return true - if the connection succeeded
- * false - otherwise
+ * Close a tcp connection.
*/
-bool
-jerry_debugger_accept_connection (void)
+static void
+jerry_debugger_ws_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */
{
- int server_socket;
- struct sockaddr_in addr;
- socklen_t sin_size = sizeof (struct sockaddr_in);
+ JERRY_ASSERT (jerry_debugger_transport_is_connected ());
- uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer) + JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE;
- JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p;
+ jerry_debugger_transport_free ((void *) header_p, sizeof (jerry_debugger_transport_header_t));
+} /* jerry_debugger_ws_close */
- 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);
+/**
+ * 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);
- 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;
+ message_p[-2] = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME;
+ message_p[-1] = (uint8_t) message_length;
- addr.sin_family = AF_INET;
- addr.sin_port = htons (JERRY_CONTEXT (debugger_port));
- addr.sin_addr.s_addr = INADDR_ANY;
+ return header_p->next_p->send (header_p->next_p, message_p - 2, message_length + 2);
+} /* jerry_debugger_ws_send */
- if ((server_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+/**
+ * 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))
{
- JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}
- int opt_value = 1;
-
- if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) == -1)
+ if (receive_context_p->message_p == NULL)
{
- close (server_socket);
- JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
- return false;
+ return true;
}
- if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr)) == -1)
- {
- close (server_socket);
- JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
- return false;
- }
+ size_t message_total_length = receive_context_p->message_total_length;
- if (listen (server_socket, 1) == -1)
+ if (message_total_length == 0)
{
- close (server_socket);
- JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
- return false;
+ /* Byte stream. */
+ if (receive_context_p->message_length < sizeof (jerry_websocket_receive_header_t))
+ {
+ receive_context_p->message_p = NULL;
+ return true;
+ }
}
-
- JERRY_DEBUG_MSG ("Waiting for client connection\n");
-
- JERRY_CONTEXT (debugger_connection) = accept (server_socket, (struct sockaddr *)&addr, &sin_size);
-
- if (JERRY_CONTEXT (debugger_connection) == -1)
+ else
{
- close (server_socket);
- JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
- return false;
+ /* Datagram packet. */
+ JERRY_ASSERT (receive_context_p->message_length >= sizeof (jerry_websocket_receive_header_t));
}
- 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);
+ uint8_t *message_p = receive_context_p->message_p;
- is_handshake_ok = jerry_process_handshake (JERRY_CONTEXT (debugger_connection),
- request_buffer_p);
-
- JMEM_FINALIZE_LOCAL_ARRAY (request_buffer_p);
-
- if (!is_handshake_ok)
+ 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_debugger_close_connection ();
+ JERRY_ERROR_MSG ("Unsupported Websocket message.\n");
+ jerry_debugger_transport_close ();
return false;
}
- if (!jerry_debugger_send_configuration (max_receive_size))
+ 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;
}
- /* Set non-blocking mode. */
- int socket_flags = fcntl (JERRY_CONTEXT (debugger_connection), F_GETFL, 0);
+ size_t message_length = (size_t) (message_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK);
- if (socket_flags < 0)
+ if (message_total_length == 0)
{
- jerry_debugger_close_connection_tcp (true);
- return false;
- }
+ size_t new_total_length = message_length + sizeof (jerry_websocket_receive_header_t);
- if (fcntl (JERRY_CONTEXT (debugger_connection), F_SETFL, socket_flags | O_NONBLOCK) == -1)
+ /* 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
{
- jerry_debugger_close_connection_tcp (true);
- return false;
+ /* Datagram packet. */
+ JERRY_ASSERT (receive_context_p->message_length == (message_length + sizeof (jerry_websocket_receive_header_t)));
}
- JERRY_DEBUG_MSG ("Connected from: %s\n", inet_ntoa (addr.sin_addr));
+ message_p += sizeof (jerry_websocket_receive_header_t);
- JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
- JERRY_CONTEXT (debugger_stop_context) = NULL;
+ receive_context_p->message_p = message_p;
+ receive_context_p->message_length = message_length;
- return true;
-} /* jerry_debugger_accept_connection */
+ /* 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;
-/**
- * Close the socket connection to the client.
- */
-inline void JERRY_ATTR_ALWAYS_INLINE
-jerry_debugger_close_connection (void)
-{
- jerry_debugger_close_connection_tcp (false);
-} /* jerry_debugger_close_connection */
+ while (message_p < message_end_p)
+ {
+ /* Invert certain bits with xor operation. */
+ *message_p = *message_p ^ *mask_p;
-/**
- * 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 (data_size <= JERRY_CONTEXT (debugger_max_send_size));
+ message_p++;
+ mask_p++;
- uint8_t *header_p = JERRY_CONTEXT (debugger_send_buffer);
- header_p[0] = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME;
- header_p[1] = (uint8_t) data_size;
+ if (JERRY_UNLIKELY (mask_p >= mask_end_p))
+ {
+ mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
+ }
+ }
- return jerry_debugger_send_tcp (header_p, data_size + JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE);
-} /* jerry_debugger_send */
+ return true;
+} /* jerry_debugger_ws_receive */
/**
- * Receive message from the client.
- *
- * Note:
- * If the function returns with true, the value of
- * JERRY_DEBUGGER_VM_STOP flag should be ignored.
+ * Initialize the websocket transportation layer.
*
- * @return true - if execution should be resumed,
+ * @return true - if the connection succeeded
* false - otherwise
*/
bool
-jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] data received from client */
+jerry_debugger_ws_create (void)
{
- 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_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
+ bool is_handshake_ok = false;
- uint8_t *recv_buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
- bool resume_exec = false;
- uint8_t expected_message_type = 0;
+ const size_t buffer_size = 1024;
+ uint8_t *request_buffer_p = (uint8_t *) jerry_debugger_transport_malloc (buffer_size);
- while (true)
+ if (!request_buffer_p)
{
- 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)
- {
- jerry_debugger_close_connection_tcp (true);
- return true;
- }
-
- byte_recv = 0;
- }
-
- 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;
- }
-
- 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;
- }
-
- 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;
- }
-
- 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));
-
- if (offset < message_total_size)
- {
- if (expected_message_type != 0)
- {
- continue;
- }
+ return false;
+ }
- return resume_exec;
- }
+ is_handshake_ok = jerry_process_handshake (request_buffer_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;
+ jerry_debugger_transport_free ((void *) request_buffer_p, buffer_size);
- while (data_p < data_end_p)
- {
- /* Invert certain bits with xor operation. */
- *data_p = *data_p ^ *mask_p;
+ if (!is_handshake_ok && jerry_debugger_transport_is_connected ())
+ {
+ return false;
+ }
- data_p++;
- mask_p++;
+ 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 (mask_p >= mask_end_p)
- {
- mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
- }
- }
+ if (!header_p)
+ {
+ return false;
+ }
- /* 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))
- {
- return true;
- }
+ header_p->close = jerry_debugger_ws_close;
+ header_p->send = jerry_debugger_ws_send;
+ header_p->receive = jerry_debugger_ws_receive;
- if (message_total_size < offset)
- {
- memmove (recv_buffer_p,
- recv_buffer_p + message_total_size,
- offset - message_total_size);
- }
+ 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);
- JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) (offset - message_total_size);
- }
-} /* jerry_debugger_receive */
+ return true;
+} /* jerry_debugger_ws_create */
#endif /* JERRY_DEBUGGER */
diff --git a/jerry-core/debugger/debugger-ws.h b/jerry-core/debugger/debugger-ws.h
index 3a7c97c8..7be74bf1 100644
--- a/jerry-core/debugger/debugger-ws.h
+++ b/jerry-core/debugger/debugger-ws.h
@@ -16,39 +16,13 @@
#ifndef DEBUGGER_WS_H
#define DEBUGGER_WS_H
-#include "ecma-globals.h"
+#include "jerryscript-debugger-transport.h"
#ifdef JERRY_DEBUGGER
/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
-/**
- * Maximum number of bytes transmitted or received.
- */
-#define JERRY_DEBUGGER_MAX_BUFFER_SIZE 128
-
-/**
- * Incoming message: next message of string data.
- */
-typedef struct
-{
- uint8_t type; /**< type of the message */
-} jerry_debugger_receive_uint8_data_part_t;
-
-/**
- * Byte data for evaluating expressions and receiving client source.
- */
-typedef struct
-{
- 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);
+bool jerry_debugger_ws_create (void);
void jerry_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len,
const uint8_t *input2, size_t input2_len,
diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c
index a3591ad7..26b52d59 100644
--- a/jerry-core/debugger/debugger.c
+++ b/jerry-core/debugger/debugger.c
@@ -20,11 +20,20 @@
#include "ecma-eval.h"
#include "ecma-objects.h"
#include "jcontext.h"
+#include "jerryscript-port.h"
#include "lit-char-helpers.h"
#ifdef JERRY_DEBUGGER
/**
+ * Incoming message: next message of string data.
+ */
+typedef struct
+{
+ uint8_t type; /**< type of the message */
+} jerry_debugger_receive_uint8_data_part_t;
+
+/**
* The number of message types in the debugger should reflect the
* debugger versioning.
*/
@@ -34,6 +43,12 @@ JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 27
debugger_version_correlates_to_message_type_count);
/**
+ * Waiting for data from the client.
+ */
+#define JERRY_DEBUGGER_RECEIVE_DATA_MODE \
+ (JERRY_DEBUGGER_BREAKPOINT_MODE | JERRY_DEBUGGER_CLIENT_SOURCE_MODE)
+
+/**
* Type cast the debugger send buffer into a specific type.
*/
#define JERRY_DEBUGGER_SEND_BUFFER_AS(type, name_p) \
@@ -71,10 +86,27 @@ jerry_debugger_free_unreferenced_byte_code (void)
} /* jerry_debugger_free_unreferenced_byte_code */
/**
+ * Send data over an active connection.
+ *
+ * @return true - if the data was sent successfully
+ * false - otherwise
+ */
+static bool
+jerry_debugger_send (size_t message_length) /**< message length in bytes */
+{
+ JERRY_ASSERT (message_length <= JERRY_CONTEXT (debugger_max_send_size));
+
+ jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
+ uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
+
+ return header_p->send (header_p, payload_p, message_length);
+} /* jerry_debugger_send */
+
+/**
* Send backtrace.
*/
static void
-jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer to the received data */
+jerry_debugger_send_backtrace (const uint8_t *recv_buffer_p) /**< pointer to the received data */
{
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_backtrace_t, get_backtrace_p);
@@ -244,23 +276,13 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
} /* jerry_debugger_send_eval */
/**
- * Suspend execution for a given time.
- * Note: If the platform does not have nanosleep or usleep, this function does not sleep at all.
- */
-void
-jerry_debugger_sleep (void)
-{
- jerry_port_sleep (JERRY_DEBUGGER_TIMEOUT);
-} /* jerry_debugger_sleep */
-
-/**
* Check received packet size.
*/
#define JERRY_DEBUGGER_CHECK_PACKET_SIZE(type) \
if (message_size != sizeof (type)) \
{ \
JERRY_ERROR_MSG ("Invalid message size\n"); \
- jerry_debugger_close_connection (); \
+ jerry_debugger_transport_close (); \
return false; \
}
@@ -270,8 +292,8 @@ jerry_debugger_sleep (void)
* @return true - if message is processed successfully
* false - otherwise
*/
-inline bool JERRY_ATTR_ALWAYS_INLINE
-jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the received data */
+static inline bool JERRY_ATTR_ALWAYS_INLINE
+jerry_debugger_process_message (const uint8_t *recv_buffer_p, /**< pointer to the received data */
uint32_t message_size, /**< message size */
bool *resume_exec_p, /**< pointer to the resume exec flag */
uint8_t *expected_message_type_p, /**< message type */
@@ -283,7 +305,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
&& !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE))
{
JERRY_ERROR_MSG ("Message requires breakpoint mode\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -298,7 +320,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
{
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
JERRY_ERROR_MSG ("Unexpected message\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -308,7 +330,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
{
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
JERRY_ERROR_MSG ("Invalid message size\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -320,7 +342,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
{
jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t));
JERRY_ERROR_MSG ("Invalid message size\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -370,7 +392,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (byte_code_free_cp != JERRY_CONTEXT (debugger_byte_code_free_tail))
{
JERRY_ERROR_MSG ("Invalid byte code free order\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -531,7 +553,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_PARSER_WAIT_MODE))
{
JERRY_ERROR_MSG ("Not in parser wait mode\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -544,7 +566,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 1)
{
JERRY_ERROR_MSG ("Invalid message size\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -558,7 +580,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (eval_size != message_size - sizeof (jerry_debugger_receive_eval_first_t))
{
JERRY_ERROR_MSG ("Invalid message size\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -594,14 +616,14 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (message_size <= sizeof (jerry_debugger_receive_client_source_first_t))
{
JERRY_ERROR_MSG ("Invalid message size\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
JERRY_ERROR_MSG ("Not in client source mode\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -616,7 +638,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
&& client_source_size != message_size - header_size)
{
JERRY_ERROR_MSG ("Invalid message size\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -653,7 +675,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
JERRY_ERROR_MSG ("Not in client source mode\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -671,7 +693,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE))
{
JERRY_ERROR_MSG ("Not in client source mode\n");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
@@ -687,12 +709,75 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the rece
default:
{
JERRY_ERROR_MSG ("Unexpected message.");
- jerry_debugger_close_connection ();
+ jerry_debugger_transport_close ();
return false;
}
}
} /* jerry_debugger_process_message */
+/**
+ * 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_debugger_transport_is_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;
+
+ while (true)
+ {
+ jerry_debugger_transport_receive_context_t context;
+ if (!jerry_debugger_transport_receive (&context))
+ {
+ JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED));
+ return true;
+ }
+
+ if (context.message_p == NULL)
+ {
+ if (expected_message_type != 0)
+ {
+ jerry_debugger_transport_sleep ();
+ continue;
+ }
+
+ return resume_exec;
+ }
+
+ /* Only datagram packets are supported. */
+ JERRY_ASSERT (context.message_total_length > 0);
+
+ /* The jerry_debugger_process_message function is inlined
+ * so passing these arguments is essentially free. */
+ if (!jerry_debugger_process_message (context.message_p,
+ (uint32_t) context.message_length,
+ &resume_exec,
+ &expected_message_type,
+ message_data_p))
+ {
+ JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED));
+ return true;
+ }
+
+ jerry_debugger_transport_receive_completed (&context);
+ }
+} /* jerry_debugger_receive */
+
+
#undef JERRY_DEBUGGER_CHECK_PACKET_SIZE
/**
@@ -727,7 +812,7 @@ jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */
while (!jerry_debugger_receive (&uint8_data))
{
- jerry_debugger_sleep ();
+ jerry_debugger_transport_sleep ();
}
if (uint8_data != NULL)
diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h
index 40239438..7321f5b3 100644
--- a/jerry-core/debugger/debugger.h
+++ b/jerry-core/debugger/debugger.h
@@ -18,6 +18,7 @@
#include "debugger-ws.h"
#include "ecma-globals.h"
+#include "jerryscript-debugger-transport.h"
#ifdef JERRY_DEBUGGER
@@ -34,22 +35,17 @@
#define JERRY_DEBUGGER_MESSAGE_FREQUENCY 5
/**
- * Sleep time in milliseconds between each jerry_debugger_receive call
+ * This constant represents that the string to be sent has no subtype.
*/
-#define JERRY_DEBUGGER_TIMEOUT 100
-
-/**
- * This constant represents that the string to be sent has no subtype.
- */
#define JERRY_DEBUGGER_NO_SUBTYPE 0
/**
* Limited resources available for the engine, so it is important to
* check the maximum buffer size. It needs to be between 64 and 256 bytes.
*/
-#if JERRY_DEBUGGER_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_MAX_BUFFER_SIZE > 256
+#if JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE > 256
#error Please define the MAX_BUFFER_SIZE between 64 and 256 bytes.
-#endif /* JERRY_DEBUGGER_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_MAX_BUFFER_SIZE > 256 */
+#endif /* JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE > 256 */
/**
* Calculate the maximum number of items for a given type
@@ -227,6 +223,15 @@ typedef enum
} jerry_debugger_output_subtype_t;
/**
+ * Byte data for evaluating expressions and receiving client source.
+ */
+typedef struct
+{
+ 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;
+
+/**
* Delayed free of byte code data.
*/
typedef struct
@@ -400,11 +405,8 @@ typedef struct
void jerry_debugger_free_unreferenced_byte_code (void);
-void jerry_debugger_sleep (void);
+bool jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p);
-bool jerry_debugger_process_message (uint8_t *recv_buffer_p, uint32_t message_size,
- bool *resume_exec_p, uint8_t *expected_message_p,
- jerry_debugger_uint8_data_t **message_data_p);
void jerry_debugger_breakpoint_hit (uint8_t message_type);
void jerry_debugger_send_type (jerry_debugger_header_type_t type);
diff --git a/jerry-core/include/jerryscript-debugger-transport.h b/jerry-core/include/jerryscript-debugger-transport.h
new file mode 100644
index 00000000..24e4e853
--- /dev/null
+++ b/jerry-core/include/jerryscript-debugger-transport.h
@@ -0,0 +1,107 @@
+/* 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.
+ */
+
+#ifndef JERRYSCRIPT_DEBUGGER_TRANSPORT_H
+#define JERRYSCRIPT_DEBUGGER_TRANSPORT_H
+
+#include <jerryscript-core.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** \addtogroup jerry-debugger-transport Jerry engine debugger interface - transport control
+ * @{
+ */
+
+/**
+ * Maximum number of bytes transmitted or received.
+ */
+#define JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE 128
+
+/**
+ * Receive message context.
+ */
+typedef struct
+{
+ uint8_t *buffer_p; /**< buffer for storing the received data */
+ size_t received_length; /**< number of currently received bytes */
+ uint8_t *message_p; /**< start of the received message */
+ size_t message_length; /**< length of the received message */
+ size_t message_total_length; /**< total length for datagram protocols,
+ * 0 for stream protocols */
+} jerry_debugger_transport_receive_context_t;
+
+/**
+ * Forward definition of jerry_debugger_transport_header_t.
+ */
+struct jerry_debugger_transport_interface_t;
+
+/**
+ * Close connection callback.
+ */
+typedef void (*jerry_debugger_transport_close_t) (struct jerry_debugger_transport_interface_t *header_p);
+
+/**
+ * Send data callback.
+ */
+typedef bool (*jerry_debugger_transport_send_t) (struct jerry_debugger_transport_interface_t *header_p,
+ uint8_t *message_p, size_t message_length);
+
+/**
+ * Receive data callback.
+ */
+typedef bool (*jerry_debugger_transport_receive_t) (struct jerry_debugger_transport_interface_t *header_p,
+ jerry_debugger_transport_receive_context_t *context_p);
+
+/**
+ * Transport layer header.
+ */
+typedef struct jerry_debugger_transport_interface_t
+{
+ /* The following fields must be filled before calling jerry_debugger_transport_add(). */
+ jerry_debugger_transport_close_t close; /**< close connection callback */
+ jerry_debugger_transport_send_t send; /**< send data callback */
+ jerry_debugger_transport_receive_t receive; /**< receive data callback */
+
+ /* The following fields are filled by jerry_debugger_transport_add(). */
+ struct jerry_debugger_transport_interface_t *next_p; /**< next transport layer */
+} jerry_debugger_transport_header_t;
+
+void * jerry_debugger_transport_malloc (size_t size);
+void jerry_debugger_transport_free (void *mem_p, size_t size);
+void jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p,
+ size_t send_message_header_size, size_t max_send_message_size,
+ size_t receive_message_header_size, size_t max_receive_message_size);
+void jerry_debugger_transport_start (void);
+
+bool jerry_debugger_transport_is_connected (void);
+void jerry_debugger_transport_close (void);
+
+bool jerry_debugger_transport_send (const uint8_t *message_p, size_t message_length);
+bool jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p);
+void jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p);
+
+void jerry_debugger_transport_sleep (void);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* !JERRYSCRIPT_DEBUGGER_TRANSPORT_H */
diff --git a/jerry-core/include/jerryscript-debugger.h b/jerry-core/include/jerryscript-debugger.h
index c6e73a79..a111c6b6 100644
--- a/jerry-core/include/jerryscript-debugger.h
+++ b/jerry-core/include/jerryscript-debugger.h
@@ -16,7 +16,7 @@
#ifndef JERRYSCRIPT_DEBUGGER_H
#define JERRYSCRIPT_DEBUGGER_H
-#include <stdbool.h>
+#include <jerryscript-core.h>
#ifdef __cplusplus
extern "C"
diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h
index f1abe682..e98d4511 100644
--- a/jerry-core/jcontext/jcontext.h
+++ b/jerry-core/jcontext/jcontext.h
@@ -27,6 +27,7 @@
#include "re-bytecode.h"
#include "vm-defines.h"
#include "jerryscript.h"
+#include "jerryscript-debugger-transport.h"
/** \addtogroup context Context
* @{
@@ -109,19 +110,18 @@ typedef struct
#endif /* JERRY_VM_EXEC_STOP */
#ifdef JERRY_DEBUGGER
- uint8_t debugger_send_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for sending messages */
- uint8_t debugger_receive_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for receiving messages */
+ uint8_t debugger_send_buffer[JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE]; /**< buffer for sending messages */
+ uint8_t debugger_receive_buffer[JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE]; /**< buffer for receiving messages */
+ jerry_debugger_transport_header_t *debugger_transport_header_p; /**< head of transport protocol chain */
uint8_t *debugger_send_buffer_payload_p; /**< start where the outgoing message can be written */
vm_frame_ctx_t *debugger_stop_context; /**< stop only if the current context is equal to this context */
jmem_cpointer_t debugger_byte_code_free_head; /**< head of byte code free linked list */
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 */
+ uint16_t debugger_received_length; /**< length of currently received bytes */
uint8_t debugger_message_delay; /**< call receive message when reaches zero */
- uint8_t debugger_max_send_size; /**< maximum amount of data that can be written */
+ uint8_t debugger_max_send_size; /**< maximum amount of data that can be sent */
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 */
#endif /* JERRY_DEBUGGER */
#ifdef JERRY_ENABLE_LINE_INFO
diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h
index 52ba022d..fd7e5405 100644
--- a/jerry-core/parser/js/js-parser-internal.h
+++ b/jerry-core/parser/js/js-parser-internal.h
@@ -232,6 +232,13 @@ typedef struct
{
uint32_t value; /**< line or offset of the breakpoint */
} parser_breakpoint_info_t;
+
+/**
+ * Maximum number of breakpoint info.
+ */
+#define PARSER_MAX_BREAKPOINT_INFO_COUNT \
+ (JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE / sizeof (parser_breakpoint_info_t))
+
#endif /* JERRY_DEBUGGER */
/**
@@ -316,8 +323,7 @@ typedef struct
#endif /* PARSER_DUMP_BYTE_CODE */
#ifdef JERRY_DEBUGGER
- /** extra data for each breakpoint */
- parser_breakpoint_info_t breakpoint_info[JERRY_DEBUGGER_MAX_BUFFER_SIZE / sizeof (parser_breakpoint_info_t)];
+ parser_breakpoint_info_t breakpoint_info[PARSER_MAX_BREAKPOINT_INFO_COUNT]; /**< breakpoint info list */
uint16_t breakpoint_info_count; /**< current breakpoint index */
parser_line_counter_t last_breakpoint_line; /**< last line where breakpoint has been inserted */
#endif /* JERRY_DEBUGGER */
diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c
index df4e61d0..bb191a9b 100644
--- a/jerry-core/parser/js/js-parser.c
+++ b/jerry-core/parser/js/js-parser.c
@@ -2949,7 +2949,7 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */
break;
}
- jerry_debugger_sleep ();
+ jerry_debugger_transport_sleep ();
}
}
#endif /* JERRY_DEBUGGER */