1 // 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.h"
31 #include "debug-agent.h"
32
33 #ifdef ENABLE_DEBUGGER_SUPPORT
34
35 namespace v8 {
36 namespace internal {
37
38 // Public V8 debugger API message handler function. This function just delegates
39 // to the debugger agent through it's data parameter.
DebuggerAgentMessageHandler(const v8::Debug::Message & message)40 void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
41 DebuggerAgent* agent = Isolate::Current()->debugger_agent_instance();
42 ASSERT(agent != NULL);
43 agent->DebuggerMessage(message);
44 }
45
46
47 // Debugger agent main thread.
Run()48 void DebuggerAgent::Run() {
49 const int kOneSecondInMicros = 1000000;
50
51 // Allow this socket to reuse port even if still in TIME_WAIT.
52 server_->SetReuseAddress(true);
53
54 // First bind the socket to the requested port.
55 bool bound = false;
56 while (!bound && !terminate_) {
57 bound = server_->Bind(port_);
58
59 // If an error occurred wait a bit before retrying. The most common error
60 // would be that the port is already in use so this avoids a busy loop and
61 // make the agent take over the port when it becomes free.
62 if (!bound) {
63 PrintF("Failed to open socket on port %d, "
64 "waiting %d ms before retrying\n", port_, kOneSecondInMicros / 1000);
65 terminate_now_->Wait(kOneSecondInMicros);
66 }
67 }
68
69 // Accept connections on the bound port.
70 while (!terminate_) {
71 bool ok = server_->Listen(1);
72 listening_->Signal();
73 if (ok) {
74 // Accept the new connection.
75 Socket* client = server_->Accept();
76 ok = client != NULL;
77 if (ok) {
78 // Create and start a new session.
79 CreateSession(client);
80 }
81 }
82 }
83 }
84
85
Shutdown()86 void DebuggerAgent::Shutdown() {
87 // Set the termination flag.
88 terminate_ = true;
89
90 // Signal termination and make the server exit either its listen call or its
91 // binding loop. This makes sure that no new sessions can be established.
92 terminate_now_->Signal();
93 server_->Shutdown();
94 Join();
95
96 // Close existing session if any.
97 CloseSession();
98 }
99
100
WaitUntilListening()101 void DebuggerAgent::WaitUntilListening() {
102 listening_->Wait();
103 }
104
105 static const char* kCreateSessionMessage =
106 "Remote debugging session already active\r\n";
107
CreateSession(Socket * client)108 void DebuggerAgent::CreateSession(Socket* client) {
109 ScopedLock with(session_access_);
110
111 // If another session is already established terminate this one.
112 if (session_ != NULL) {
113 client->Send(kCreateSessionMessage, StrLength(kCreateSessionMessage));
114 delete client;
115 return;
116 }
117
118 // Create a new session and hook up the debug message handler.
119 session_ = new DebuggerAgentSession(this, client);
120 isolate_->debugger()->SetMessageHandler(DebuggerAgentMessageHandler);
121 session_->Start();
122 }
123
124
CloseSession()125 void DebuggerAgent::CloseSession() {
126 ScopedLock with(session_access_);
127
128 // Terminate the session.
129 if (session_ != NULL) {
130 session_->Shutdown();
131 session_->Join();
132 delete session_;
133 session_ = NULL;
134 }
135 }
136
137
DebuggerMessage(const v8::Debug::Message & message)138 void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) {
139 ScopedLock with(session_access_);
140
141 // Forward the message handling to the session.
142 if (session_ != NULL) {
143 v8::String::Value val(message.GetJSON());
144 session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(*val),
145 val.length()));
146 }
147 }
148
149
OnSessionClosed(DebuggerAgentSession * session)150 void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) {
151 // Don't do anything during termination.
152 if (terminate_) {
153 return;
154 }
155
156 // Terminate the session.
157 ScopedLock with(session_access_);
158 ASSERT(session == session_);
159 if (session == session_) {
160 CloseSession();
161 }
162 }
163
164
Run()165 void DebuggerAgentSession::Run() {
166 // Send the hello message.
167 bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_);
168 if (!ok) return;
169
170 while (true) {
171 // Read data from the debugger front end.
172 SmartArrayPointer<char> message =
173 DebuggerAgentUtil::ReceiveMessage(client_);
174
175 const char* msg = *message;
176 bool is_closing_session = (msg == NULL);
177
178 if (msg == NULL) {
179 // If we lost the connection, then simulate a disconnect msg:
180 msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}";
181
182 } else {
183 // Check if we're getting a disconnect request:
184 const char* disconnectRequestStr =
185 "\"type\":\"request\",\"command\":\"disconnect\"}";
186 const char* result = strstr(msg, disconnectRequestStr);
187 if (result != NULL) {
188 is_closing_session = true;
189 }
190 }
191
192 // Convert UTF-8 to UTF-16.
193 unibrow::Utf8InputBuffer<> buf(msg, StrLength(msg));
194 int len = 0;
195 while (buf.has_more()) {
196 buf.GetNext();
197 len++;
198 }
199 ScopedVector<int16_t> temp(len + 1);
200 buf.Reset(msg, StrLength(msg));
201 for (int i = 0; i < len; i++) {
202 temp[i] = buf.GetNext();
203 }
204
205 // Send the request received to the debugger.
206 v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp.start()),
207 len,
208 NULL,
209 reinterpret_cast<v8::Isolate*>(agent_->isolate()));
210
211 if (is_closing_session) {
212 // Session is closed.
213 agent_->OnSessionClosed(this);
214 return;
215 }
216 }
217 }
218
219
DebuggerMessage(Vector<uint16_t> message)220 void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
221 DebuggerAgentUtil::SendMessage(client_, message);
222 }
223
224
Shutdown()225 void DebuggerAgentSession::Shutdown() {
226 // Shutdown the socket to end the blocking receive.
227 client_->Shutdown();
228 }
229
230
231 const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
232
233
ReceiveMessage(const Socket * conn)234 SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
235 int received;
236
237 // Read header.
238 int content_length = 0;
239 while (true) {
240 const int kHeaderBufferSize = 80;
241 char header_buffer[kHeaderBufferSize];
242 int header_buffer_position = 0;
243 char c = '\0'; // One character receive buffer.
244 char prev_c = '\0'; // Previous character.
245
246 // Read until CRLF.
247 while (!(c == '\n' && prev_c == '\r')) {
248 prev_c = c;
249 received = conn->Receive(&c, 1);
250 if (received <= 0) {
251 PrintF("Error %d\n", Socket::LastError());
252 return SmartArrayPointer<char>();
253 }
254
255 // Add character to header buffer.
256 if (header_buffer_position < kHeaderBufferSize) {
257 header_buffer[header_buffer_position++] = c;
258 }
259 }
260
261 // Check for end of header (empty header line).
262 if (header_buffer_position == 2) { // Receive buffer contains CRLF.
263 break;
264 }
265
266 // Terminate header.
267 ASSERT(header_buffer_position > 1); // At least CRLF is received.
268 ASSERT(header_buffer_position <= kHeaderBufferSize);
269 header_buffer[header_buffer_position - 2] = '\0';
270
271 // Split header.
272 char* key = header_buffer;
273 char* value = NULL;
274 for (int i = 0; header_buffer[i] != '\0'; i++) {
275 if (header_buffer[i] == ':') {
276 header_buffer[i] = '\0';
277 value = header_buffer + i + 1;
278 while (*value == ' ') {
279 value++;
280 }
281 break;
282 }
283 }
284
285 // Check that key is Content-Length.
286 if (strcmp(key, kContentLength) == 0) {
287 // Get the content length value if present and within a sensible range.
288 if (value == NULL || strlen(value) > 7) {
289 return SmartArrayPointer<char>();
290 }
291 for (int i = 0; value[i] != '\0'; i++) {
292 // Bail out if illegal data.
293 if (value[i] < '0' || value[i] > '9') {
294 return SmartArrayPointer<char>();
295 }
296 content_length = 10 * content_length + (value[i] - '0');
297 }
298 } else {
299 // For now just print all other headers than Content-Length.
300 PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
301 }
302 }
303
304 // Return now if no body.
305 if (content_length == 0) {
306 return SmartArrayPointer<char>();
307 }
308
309 // Read body.
310 char* buffer = NewArray<char>(content_length + 1);
311 received = ReceiveAll(conn, buffer, content_length);
312 if (received < content_length) {
313 PrintF("Error %d\n", Socket::LastError());
314 return SmartArrayPointer<char>();
315 }
316 buffer[content_length] = '\0';
317
318 return SmartArrayPointer<char>(buffer);
319 }
320
321
SendConnectMessage(const Socket * conn,const char * embedding_host)322 bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
323 const char* embedding_host) {
324 static const int kBufferSize = 80;
325 char buffer[kBufferSize]; // Sending buffer.
326 bool ok;
327 int len;
328
329 // Send the header.
330 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
331 "Type: connect\r\n");
332 ok = conn->Send(buffer, len);
333 if (!ok) return false;
334
335 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
336 "V8-Version: %s\r\n", v8::V8::GetVersion());
337 ok = conn->Send(buffer, len);
338 if (!ok) return false;
339
340 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
341 "Protocol-Version: 1\r\n");
342 ok = conn->Send(buffer, len);
343 if (!ok) return false;
344
345 if (embedding_host != NULL) {
346 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
347 "Embedding-Host: %s\r\n", embedding_host);
348 ok = conn->Send(buffer, len);
349 if (!ok) return false;
350 }
351
352 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
353 "%s: 0\r\n", kContentLength);
354 ok = conn->Send(buffer, len);
355 if (!ok) return false;
356
357 // Terminate header with empty line.
358 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
359 ok = conn->Send(buffer, len);
360 if (!ok) return false;
361
362 // No body for connect message.
363
364 return true;
365 }
366
367
SendMessage(const Socket * conn,const Vector<uint16_t> message)368 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
369 const Vector<uint16_t> message) {
370 static const int kBufferSize = 80;
371 char buffer[kBufferSize]; // Sending buffer both for header and body.
372
373 // Calculate the message size in UTF-8 encoding.
374 int utf8_len = 0;
375 int previous = unibrow::Utf16::kNoPreviousCharacter;
376 for (int i = 0; i < message.length(); i++) {
377 uint16_t character = message[i];
378 utf8_len += unibrow::Utf8::Length(character, previous);
379 previous = character;
380 }
381
382 // Send the header.
383 int len;
384 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
385 "%s: %d\r\n", kContentLength, utf8_len);
386 conn->Send(buffer, len);
387
388 // Terminate header with empty line.
389 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
390 conn->Send(buffer, len);
391
392 // Send message body as UTF-8.
393 int buffer_position = 0; // Current buffer position.
394 previous = unibrow::Utf16::kNoPreviousCharacter;
395 for (int i = 0; i < message.length(); i++) {
396 // Write next UTF-8 encoded character to buffer.
397 uint16_t character = message[i];
398 buffer_position +=
399 unibrow::Utf8::Encode(buffer + buffer_position, character, previous);
400 ASSERT(buffer_position < kBufferSize);
401
402 // Send buffer if full or last character is encoded.
403 if (kBufferSize - buffer_position <
404 unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit ||
405 i == message.length() - 1) {
406 if (unibrow::Utf16::IsLeadSurrogate(character)) {
407 const int kEncodedSurrogateLength =
408 unibrow::Utf16::kUtf8BytesToCodeASurrogate;
409 ASSERT(buffer_position >= kEncodedSurrogateLength);
410 conn->Send(buffer, buffer_position - kEncodedSurrogateLength);
411 for (int i = 0; i < kEncodedSurrogateLength; i++) {
412 buffer[i] = buffer[buffer_position + i];
413 }
414 buffer_position = kEncodedSurrogateLength;
415 } else {
416 conn->Send(buffer, buffer_position);
417 buffer_position = 0;
418 }
419 }
420 previous = character;
421 }
422
423 return true;
424 }
425
426
SendMessage(const Socket * conn,const v8::Handle<v8::String> request)427 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
428 const v8::Handle<v8::String> request) {
429 static const int kBufferSize = 80;
430 char buffer[kBufferSize]; // Sending buffer both for header and body.
431
432 // Convert the request to UTF-8 encoding.
433 v8::String::Utf8Value utf8_request(request);
434
435 // Send the header.
436 int len;
437 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
438 "Content-Length: %d\r\n", utf8_request.length());
439 conn->Send(buffer, len);
440
441 // Terminate header with empty line.
442 len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
443 conn->Send(buffer, len);
444
445 // Send message body as UTF-8.
446 conn->Send(*utf8_request, utf8_request.length());
447
448 return true;
449 }
450
451
452 // Receive the full buffer before returning unless an error occours.
ReceiveAll(const Socket * conn,char * data,int len)453 int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
454 int total_received = 0;
455 while (total_received < len) {
456 int received = conn->Receive(data + total_received, len - total_received);
457 if (received <= 0) {
458 return total_received;
459 }
460 total_received += received;
461 }
462 return total_received;
463 }
464
465 } } // namespace v8::internal
466
467 #endif // ENABLE_DEBUGGER_SUPPORT
468