Home | History | Annotate | Download | only in src
      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.
     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.
     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 
     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 
    101 void DebuggerAgent::WaitUntilListening() {
    102   listening_->Wait();
    103 }
    104 
    105 static const char* kCreateSessionMessage =
    106     "Remote debugging session already active\r\n";
    107 
    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 
    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 
    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 
    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 
    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 
    220 void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
    221   DebuggerAgentUtil::SendMessage(client_, message);
    222 }
    223 
    224 
    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 
    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 
    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 
    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 
    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.
    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