blob: 9d5cace03ba1095dbcf27c90f9a271b75a913cc7 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29#include "v8.h"
30#include "debug-agent.h"
31
32#ifdef ENABLE_DEBUGGER_SUPPORT
33namespace v8 {
34namespace internal {
35
36// Public V8 debugger API message handler function. This function just delegates
37// to the debugger agent through it's data parameter.
38void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
39 DebuggerAgent::instance_->DebuggerMessage(message);
40}
41
42// static
43DebuggerAgent* DebuggerAgent::instance_ = NULL;
44
45// Debugger agent main thread.
46void DebuggerAgent::Run() {
47 const int kOneSecondInMicros = 1000000;
48
49 // Allow this socket to reuse port even if still in TIME_WAIT.
50 server_->SetReuseAddress(true);
51
52 // First bind the socket to the requested port.
53 bool bound = false;
54 while (!bound && !terminate_) {
55 bound = server_->Bind(port_);
56
57 // If an error occoured wait a bit before retrying. The most common error
58 // would be that the port is already in use so this avoids a busy loop and
59 // make the agent take over the port when it becomes free.
60 if (!bound) {
61 terminate_now_->Wait(kOneSecondInMicros);
62 }
63 }
64
65 // Accept connections on the bound port.
66 while (!terminate_) {
67 bool ok = server_->Listen(1);
68 listening_->Signal();
69 if (ok) {
70 // Accept the new connection.
71 Socket* client = server_->Accept();
72 ok = client != NULL;
73 if (ok) {
74 // Create and start a new session.
75 CreateSession(client);
76 }
77 }
78 }
79}
80
81
82void DebuggerAgent::Shutdown() {
83 // Set the termination flag.
84 terminate_ = true;
85
86 // Signal termination and make the server exit either its listen call or its
87 // binding loop. This makes sure that no new sessions can be established.
88 terminate_now_->Signal();
89 server_->Shutdown();
90 Join();
91
92 // Close existing session if any.
93 CloseSession();
94}
95
96
97void DebuggerAgent::WaitUntilListening() {
98 listening_->Wait();
99}
100
101void DebuggerAgent::CreateSession(Socket* client) {
102 ScopedLock with(session_access_);
103
104 // If another session is already established terminate this one.
105 if (session_ != NULL) {
106 static const char* message = "Remote debugging session already active\r\n";
107
108 client->Send(message, strlen(message));
109 delete client;
110 return;
111 }
112
113 // Create a new session and hook up the debug message handler.
114 session_ = new DebuggerAgentSession(this, client);
115 v8::Debug::SetMessageHandler2(DebuggerAgentMessageHandler);
116 session_->Start();
117}
118
119
120void DebuggerAgent::CloseSession() {
121 ScopedLock with(session_access_);
122
123 // Terminate the session.
124 if (session_ != NULL) {
125 session_->Shutdown();
126 session_->Join();
127 delete session_;
128 session_ = NULL;
129 }
130}
131
132
133void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) {
134 ScopedLock with(session_access_);
135
136 // Forward the message handling to the session.
137 if (session_ != NULL) {
138 v8::String::Value val(message.GetJSON());
139 session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(*val),
140 val.length()));
141 }
142}
143
144
145void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) {
146 // Don't do anything during termination.
147 if (terminate_) {
148 return;
149 }
150
151 // Terminate the session.
152 ScopedLock with(session_access_);
153 ASSERT(session == session_);
154 if (session == session_) {
155 CloseSession();
156 }
157}
158
159
160void DebuggerAgentSession::Run() {
161 // Send the hello message.
162 bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_);
163 if (!ok) return;
164
165 while (true) {
166 // Read data from the debugger front end.
167 SmartPointer<char> message = DebuggerAgentUtil::ReceiveMessage(client_);
168 if (*message == NULL) {
169 // Session is closed.
170 agent_->OnSessionClosed(this);
171 return;
172 }
173
174 // Convert UTF-8 to UTF-16.
175 unibrow::Utf8InputBuffer<> buf(*message, strlen(*message));
176 int len = 0;
177 while (buf.has_more()) {
178 buf.GetNext();
179 len++;
180 }
181 int16_t* temp = NewArray<int16_t>(len + 1);
182 buf.Reset(*message, strlen(*message));
183 for (int i = 0; i < len; i++) {
184 temp[i] = buf.GetNext();
185 }
186
187 // Send the request received to the debugger.
188 v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp), len);
189 DeleteArray(temp);
190 }
191}
192
193
194void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
195 DebuggerAgentUtil::SendMessage(client_, message);
196}
197
198
199void DebuggerAgentSession::Shutdown() {
200 // Shutdown the socket to end the blocking receive.
201 client_->Shutdown();
202}
203
204
205const char* DebuggerAgentUtil::kContentLength = "Content-Length";
206int DebuggerAgentUtil::kContentLengthSize = strlen(kContentLength);
207
208
209SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
210 int received;
211
212 // Read header.
213 int content_length = 0;
214 while (true) {
215 const int kHeaderBufferSize = 80;
216 char header_buffer[kHeaderBufferSize];
217 int header_buffer_position = 0;
218 char c = '\0'; // One character receive buffer.
219 char prev_c = '\0'; // Previous character.
220
221 // Read until CRLF.
222 while (!(c == '\n' && prev_c == '\r')) {
223 prev_c = c;
224 received = conn->Receive(&c, 1);
225 if (received <= 0) {
226 PrintF("Error %d\n", Socket::LastError());
227 return SmartPointer<char>();
228 }
229
230 // Add character to header buffer.
231 if (header_buffer_position < kHeaderBufferSize) {
232 header_buffer[header_buffer_position++] = c;
233 }
234 }
235
236 // Check for end of header (empty header line).
237 if (header_buffer_position == 2) { // Receive buffer contains CRLF.
238 break;
239 }
240
241 // Terminate header.
242 ASSERT(header_buffer_position > 1); // At least CRLF is received.
243 ASSERT(header_buffer_position <= kHeaderBufferSize);
244 header_buffer[header_buffer_position - 2] = '\0';
245
246 // Split header.
247 char* key = header_buffer;
248 char* value = NULL;
249 for (int i = 0; header_buffer[i] != '\0'; i++) {
250 if (header_buffer[i] == ':') {
251 header_buffer[i] = '\0';
252 value = header_buffer + i + 1;
253 while (*value == ' ') {
254 value++;
255 }
256 break;
257 }
258 }
259
260 // Check that key is Content-Length.
261 if (strcmp(key, kContentLength) == 0) {
262 // Get the content length value if present and within a sensible range.
263 if (value == NULL || strlen(value) > 7) {
264 return SmartPointer<char>();
265 }
266 for (int i = 0; value[i] != '\0'; i++) {
267 // Bail out if illegal data.
268 if (value[i] < '0' || value[i] > '9') {
269 return SmartPointer<char>();
270 }
271 content_length = 10 * content_length + (value[i] - '0');
272 }
273 } else {
274 // For now just print all other headers than Content-Length.
275 PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
276 }
277 }
278
279 // Return now if no body.
280 if (content_length == 0) {
281 return SmartPointer<char>();
282 }
283
284 // Read body.
285 char* buffer = NewArray<char>(content_length + 1);
286 received = ReceiveAll(conn, buffer, content_length);
287 if (received < content_length) {
288 PrintF("Error %d\n", Socket::LastError());
289 return SmartPointer<char>();
290 }
291 buffer[content_length] = '\0';
292
293 return SmartPointer<char>(buffer);
294}
295
296
297bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
298 const char* embedding_host) {
299 static const int kBufferSize = 80;
300 char buffer[kBufferSize]; // Sending buffer.
301 bool ok;
302 int len;
303
304 // Send the header.
305 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
306 "Type: connect\r\n");
307 ok = conn->Send(buffer, len);
308 if (!ok) return false;
309
310 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
311 "V8-Version: %s\r\n", v8::V8::GetVersion());
312 ok = conn->Send(buffer, len);
313 if (!ok) return false;
314
315 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
316 "Protocol-Version: 1\r\n");
317 ok = conn->Send(buffer, len);
318 if (!ok) return false;
319
320 if (embedding_host != NULL) {
321 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
322 "Embedding-Host: %s\r\n", embedding_host);
323 ok = conn->Send(buffer, len);
324 if (!ok) return false;
325 }
326
327 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
328 "%s: 0\r\n", kContentLength);
329 ok = conn->Send(buffer, len);
330 if (!ok) return false;
331
332 // Terminate header with empty line.
333 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
334 ok = conn->Send(buffer, len);
335 if (!ok) return false;
336
337 // No body for connect message.
338
339 return true;
340}
341
342
343bool DebuggerAgentUtil::SendMessage(const Socket* conn,
344 const Vector<uint16_t> message) {
345 static const int kBufferSize = 80;
346 char buffer[kBufferSize]; // Sending buffer both for header and body.
347
348 // Calculate the message size in UTF-8 encoding.
349 int utf8_len = 0;
350 for (int i = 0; i < message.length(); i++) {
351 utf8_len += unibrow::Utf8::Length(message[i]);
352 }
353
354 // Send the header.
355 int len;
356 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
357 "%s: %d\r\n", kContentLength, utf8_len);
358 conn->Send(buffer, len);
359
360 // Terminate header with empty line.
361 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
362 conn->Send(buffer, len);
363
364 // Send message body as UTF-8.
365 int buffer_position = 0; // Current buffer position.
366 for (int i = 0; i < message.length(); i++) {
367 // Write next UTF-8 encoded character to buffer.
368 buffer_position +=
369 unibrow::Utf8::Encode(buffer + buffer_position, message[i]);
370 ASSERT(buffer_position < kBufferSize);
371
372 // Send buffer if full or last character is encoded.
373 if (kBufferSize - buffer_position < 3 || i == message.length() - 1) {
374 conn->Send(buffer, buffer_position);
375 buffer_position = 0;
376 }
377 }
378
379 return true;
380}
381
382
383bool DebuggerAgentUtil::SendMessage(const Socket* conn,
384 const v8::Handle<v8::String> request) {
385 static const int kBufferSize = 80;
386 char buffer[kBufferSize]; // Sending buffer both for header and body.
387
388 // Convert the request to UTF-8 encoding.
389 v8::String::Utf8Value utf8_request(request);
390
391 // Send the header.
392 int len;
393 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
394 "Content-Length: %d\r\n", utf8_request.length());
395 conn->Send(buffer, len);
396
397 // Terminate header with empty line.
398 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
399 conn->Send(buffer, len);
400
401 // Send message body as UTF-8.
402 conn->Send(*utf8_request, utf8_request.length());
403
404 return true;
405}
406
407
408// Receive the full buffer before returning unless an error occours.
409int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
410 int total_received = 0;
411 while (total_received < len) {
412 int received = conn->Receive(data + total_received, len - total_received);
413 if (received <= 0) {
414 return total_received;
415 }
416 total_received += received;
417 }
418 return total_received;
419}
420
421} } // namespace v8::internal
422
423#endif // ENABLE_DEBUGGER_SUPPORT