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