| 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 |