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