1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "debugger.h"
17#include "jcontext.h"
18#include "jerryscript.h"
19
20#if ENABLED (JERRY_DEBUGGER)
21
22/**
23 * Minimum number of bytes transmitted or received.
24 */
25#define JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE 64
26
27/**
28 * Sleep time in milliseconds between each jerry_debugger_receive call
29 */
30#define JERRY_DEBUGGER_TRANSPORT_TIMEOUT 100
31
32/**
33 * Add a new transport layer.
34 */
35void
36jerry_debugger_transport_add (jerry_debugger_transport_header_t *header_p, /**< transport implementation */
37 size_t send_message_header_size, /**< header bytes reserved for outgoing messages */
38 size_t max_send_message_size, /**< maximum number of bytes transmitted in a message */
39 size_t receive_message_header_size, /**< header bytes reserved for incoming messages */
40 size_t max_receive_message_size) /**< maximum number of bytes received in a message */
41{
42 JERRY_ASSERT (max_send_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE
43 && max_receive_message_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE);
44
45 header_p->next_p = JERRY_CONTEXT (debugger_transport_header_p);
46 JERRY_CONTEXT (debugger_transport_header_p) = header_p;
47
48 uint8_t *payload_p;
49 size_t max_send_size;
50 size_t max_receive_size;
51
52 if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
53 {
54 payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
55 max_send_size = JERRY_CONTEXT (debugger_max_send_size);
56 max_receive_size = JERRY_CONTEXT (debugger_max_receive_size);
57 }
58 else
59 {
60 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED);
61 payload_p = JERRY_CONTEXT (debugger_send_buffer);
62 max_send_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
63 max_receive_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE;
64 }
65
66 JERRY_ASSERT (max_send_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + send_message_header_size);
67 JERRY_ASSERT (max_receive_size > JERRY_DEBUGGER_TRANSPORT_MIN_BUFFER_SIZE + receive_message_header_size);
68
69 JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p + send_message_header_size;
70
71 max_send_size = max_send_size - send_message_header_size;
72 max_receive_size = max_receive_size - receive_message_header_size;
73
74 if (max_send_size > max_send_message_size)
75 {
76 max_send_size = max_send_message_size;
77 }
78
79 if (max_receive_size > max_receive_message_size)
80 {
81 max_receive_size = max_receive_message_size;
82 }
83
84 JERRY_CONTEXT (debugger_max_send_size) = (uint8_t) max_send_size;
85 JERRY_CONTEXT (debugger_max_receive_size) = (uint8_t) max_receive_size;
86} /* jerry_debugger_transport_add */
87
88/**
89 * Starts the communication to the debugger client.
90 * Must be called after the connection is successfully established.
91 */
92void
93jerry_debugger_transport_start (void)
94{
95 JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
96
97 if (jerry_debugger_send_configuration (JERRY_CONTEXT (debugger_max_receive_size)))
98 {
99 JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
100 JERRY_CONTEXT (debugger_stop_context) = NULL;
101 }
102} /* jerry_debugger_transport_start */
103
104/**
105 * Returns true if a debugger client is connected.
106 *
107 * @return true - a debugger client is connected,
108 * false - otherwise
109 */
110bool
111jerry_debugger_transport_is_connected (void)
112{
113 return (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0;
114} /* jerry_debugger_transport_is_connected */
115
116/**
117 * Notifies the debugger server that the connection is closed.
118 */
119void
120jerry_debugger_transport_close (void)
121{
122 if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED))
123 {
124 return;
125 }
126
127 JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE;
128
129 jerry_debugger_transport_header_t *current_p = JERRY_CONTEXT (debugger_transport_header_p);
130
131 JERRY_ASSERT (current_p != NULL);
132
133 do
134 {
135 jerry_debugger_transport_header_t *next_p = current_p->next_p;
136
137 current_p->close (current_p);
138
139 current_p = next_p;
140 }
141 while (current_p != NULL);
142
143 jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Debugger client connection closed.\n");
144
145 jerry_debugger_free_unreferenced_byte_code ();
146} /* jerry_debugger_transport_close */
147
148/**
149 * Send data over the current connection
150 *
151 * @return true - data sent successfully,
152 * false - connection closed
153 */
154bool
155jerry_debugger_transport_send (const uint8_t *message_p, /**< message to be sent */
156 size_t message_length) /**< message length in bytes */
157{
158 JERRY_ASSERT (jerry_debugger_transport_is_connected ());
159 JERRY_ASSERT (message_length > 0);
160
161 jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
162 uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p);
163 size_t max_send_size = JERRY_CONTEXT (debugger_max_send_size);
164
165 do
166 {
167 size_t fragment_length = (message_length <= max_send_size ? message_length
168 : max_send_size);
169
170 memcpy (payload_p, message_p, fragment_length);
171
172 if (!header_p->send (header_p, payload_p, fragment_length))
173 {
174 return false;
175 }
176
177 message_p += fragment_length;
178 message_length -= fragment_length;
179 }
180 while (message_length > 0);
181
182 return true;
183} /* jerry_debugger_transport_send */
184
185/**
186 * Receive data from the current connection
187 *
188 * Note:
189 * A message is received if message_start_p is not NULL
190 *
191 * @return true - function successfully completed,
192 * false - connection closed
193 */
194bool
195jerry_debugger_transport_receive (jerry_debugger_transport_receive_context_t *context_p) /**< [out] receive
196 * context */
197{
198 JERRY_ASSERT (jerry_debugger_transport_is_connected ());
199
200 context_p->buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
201 context_p->received_length = JERRY_CONTEXT (debugger_received_length);
202 context_p->message_p = NULL;
203 context_p->message_length = 0;
204 context_p->message_total_length = 0;
205
206 jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p);
207
208 return header_p->receive (header_p, context_p);
209} /* jerry_debugger_transport_receive */
210
211/**
212 * Clear the message buffer after the message is processed
213 */
214void
215jerry_debugger_transport_receive_completed (jerry_debugger_transport_receive_context_t *context_p) /**< receive
216 * context */
217{
218 JERRY_ASSERT (context_p->message_p != NULL);
219 JERRY_ASSERT (context_p->buffer_p == JERRY_CONTEXT (debugger_receive_buffer));
220
221 size_t message_total_length = context_p->message_total_length;
222 size_t received_length = context_p->received_length;
223
224 JERRY_ASSERT (message_total_length <= received_length);
225
226 if (message_total_length == 0 || message_total_length == received_length)
227 {
228 /* All received data is processed. */
229 JERRY_CONTEXT (debugger_received_length) = 0;
230 return;
231 }
232
233 uint8_t *buffer_p = context_p->buffer_p;
234 received_length -= message_total_length;
235
236 memmove (buffer_p, buffer_p + message_total_length, received_length);
237
238 JERRY_CONTEXT (debugger_received_length) = (uint16_t) received_length;
239} /* jerry_debugger_transport_receive_completed */
240
241/**
242 * Suspend execution for a predefined time (JERRY_DEBUGGER_TRANSPORT_TIMEOUT ms).
243 */
244void
245jerry_debugger_transport_sleep (void)
246{
247 jerry_port_sleep (JERRY_DEBUGGER_TRANSPORT_TIMEOUT);
248} /* jerry_debugger_transport_sleep */
249
250#endif /* ENABLED (JERRY_DEBUGGER) */
251