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(isolate(), this, client);
    120   v8::Debug::SetMessageHandler2(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     SmartPointer<char> message = DebuggerAgentUtil::ReceiveMessage(client_);
    173 
    174     const char* msg = *message;
    175     bool is_closing_session = (msg == NULL);
    176 
    177     if (msg == NULL) {
    178       // If we lost the connection, then simulate a disconnect msg:
    179       msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}";
    180 
    181     } else {
    182       // Check if we're getting a disconnect request:
    183       const char* disconnectRequestStr =
    184           "\"type\":\"request\",\"command\":\"disconnect\"}";
    185       const char* result = strstr(msg, disconnectRequestStr);
    186       if (result != NULL) {
    187         is_closing_session = true;
    188       }
    189     }
    190 
    191     // Convert UTF-8 to UTF-16.
    192     unibrow::Utf8InputBuffer<> buf(msg, StrLength(msg));
    193     int len = 0;
    194     while (buf.has_more()) {
    195       buf.GetNext();
    196       len++;
    197     }
    198     ScopedVector<int16_t> temp(len + 1);
    199     buf.Reset(msg, StrLength(msg));
    200     for (int i = 0; i < len; i++) {
    201       temp[i] = buf.GetNext();
    202     }
    203 
    204     // Send the request received to the debugger.
    205     v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp.start()),
    206                            len);
    207 
    208     if (is_closing_session) {
    209       // Session is closed.
    210       agent_->OnSessionClosed(this);
    211       return;
    212     }
    213   }
    214 }
    215 
    216 
    217 void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
    218   DebuggerAgentUtil::SendMessage(client_, message);
    219 }
    220 
    221 
    222 void DebuggerAgentSession::Shutdown() {
    223   // Shutdown the socket to end the blocking receive.
    224   client_->Shutdown();
    225 }
    226 
    227 
    228 const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
    229 const int DebuggerAgentUtil::kContentLengthSize =
    230     StrLength(kContentLength);
    231 
    232 
    233 SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
    234   int received;
    235 
    236   // Read header.
    237   int content_length = 0;
    238   while (true) {
    239     const int kHeaderBufferSize = 80;
    240     char header_buffer[kHeaderBufferSize];
    241     int header_buffer_position = 0;
    242     char c = '\0';  // One character receive buffer.
    243     char prev_c = '\0';  // Previous character.
    244 
    245     // Read until CRLF.
    246     while (!(c == '\n' && prev_c == '\r')) {
    247       prev_c = c;
    248       received = conn->Receive(&c, 1);
    249       if (received <= 0) {
    250         PrintF("Error %d\n", Socket::LastError());
    251         return SmartPointer<char>();
    252       }
    253 
    254       // Add character to header buffer.
    255       if (header_buffer_position < kHeaderBufferSize) {
    256         header_buffer[header_buffer_position++] = c;
    257       }
    258     }
    259 
    260     // Check for end of header (empty header line).
    261     if (header_buffer_position == 2) {  // Receive buffer contains CRLF.
    262       break;
    263     }
    264 
    265     // Terminate header.
    266     ASSERT(header_buffer_position > 1);  // At least CRLF is received.
    267     ASSERT(header_buffer_position <= kHeaderBufferSize);
    268     header_buffer[header_buffer_position - 2] = '\0';
    269 
    270     // Split header.
    271     char* key = header_buffer;
    272     char* value = NULL;
    273     for (int i = 0; header_buffer[i] != '\0'; i++) {
    274       if (header_buffer[i] == ':') {
    275         header_buffer[i] = '\0';
    276         value = header_buffer + i + 1;
    277         while (*value == ' ') {
    278           value++;
    279         }
    280         break;
    281       }
    282     }
    283 
    284     // Check that key is Content-Length.
    285     if (strcmp(key, kContentLength) == 0) {
    286       // Get the content length value if present and within a sensible range.
    287       if (value == NULL || strlen(value) > 7) {
    288         return SmartPointer<char>();
    289       }
    290       for (int i = 0; value[i] != '\0'; i++) {
    291         // Bail out if illegal data.
    292         if (value[i] < '0' || value[i] > '9') {
    293           return SmartPointer<char>();
    294         }
    295         content_length = 10 * content_length + (value[i] - '0');
    296       }
    297     } else {
    298       // For now just print all other headers than Content-Length.
    299       PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
    300     }
    301   }
    302 
    303   // Return now if no body.
    304   if (content_length == 0) {
    305     return SmartPointer<char>();
    306   }
    307 
    308   // Read body.
    309   char* buffer = NewArray<char>(content_length + 1);
    310   received = ReceiveAll(conn, buffer, content_length);
    311   if (received < content_length) {
    312     PrintF("Error %d\n", Socket::LastError());
    313     return SmartPointer<char>();
    314   }
    315   buffer[content_length] = '\0';
    316 
    317   return SmartPointer<char>(buffer);
    318 }
    319 
    320 
    321 bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
    322                                            const char* embedding_host) {
    323   static const int kBufferSize = 80;
    324   char buffer[kBufferSize];  // Sending buffer.
    325   bool ok;
    326   int len;
    327 
    328   // Send the header.
    329   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
    330                      "Type: connect\r\n");
    331   ok = conn->Send(buffer, len);
    332   if (!ok) return false;
    333 
    334   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
    335                      "V8-Version: %s\r\n", v8::V8::GetVersion());
    336   ok = conn->Send(buffer, len);
    337   if (!ok) return false;
    338 
    339   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
    340                      "Protocol-Version: 1\r\n");
    341   ok = conn->Send(buffer, len);
    342   if (!ok) return false;
    343 
    344   if (embedding_host != NULL) {
    345     len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
    346                        "Embedding-Host: %s\r\n", embedding_host);
    347     ok = conn->Send(buffer, len);
    348     if (!ok) return false;
    349   }
    350 
    351   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
    352                      "%s: 0\r\n", kContentLength);
    353   ok = conn->Send(buffer, len);
    354   if (!ok) return false;
    355 
    356   // Terminate header with empty line.
    357   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
    358   ok = conn->Send(buffer, len);
    359   if (!ok) return false;
    360 
    361   // No body for connect message.
    362 
    363   return true;
    364 }
    365 
    366 
    367 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
    368                                     const Vector<uint16_t> message) {
    369   static const int kBufferSize = 80;
    370   char buffer[kBufferSize];  // Sending buffer both for header and body.
    371 
    372   // Calculate the message size in UTF-8 encoding.
    373   int utf8_len = 0;
    374   for (int i = 0; i < message.length(); i++) {
    375     utf8_len += unibrow::Utf8::Length(message[i]);
    376   }
    377 
    378   // Send the header.
    379   int len;
    380   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
    381                      "%s: %d\r\n", kContentLength, utf8_len);
    382   conn->Send(buffer, len);
    383 
    384   // Terminate header with empty line.
    385   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
    386   conn->Send(buffer, len);
    387 
    388   // Send message body as UTF-8.
    389   int buffer_position = 0;  // Current buffer position.
    390   for (int i = 0; i < message.length(); i++) {
    391     // Write next UTF-8 encoded character to buffer.
    392     buffer_position +=
    393         unibrow::Utf8::Encode(buffer + buffer_position, message[i]);
    394     ASSERT(buffer_position < kBufferSize);
    395 
    396     // Send buffer if full or last character is encoded.
    397     if (kBufferSize - buffer_position < 3 || i == message.length() - 1) {
    398       conn->Send(buffer, buffer_position);
    399       buffer_position = 0;
    400     }
    401   }
    402 
    403   return true;
    404 }
    405 
    406 
    407 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
    408                                     const v8::Handle<v8::String> request) {
    409   static const int kBufferSize = 80;
    410   char buffer[kBufferSize];  // Sending buffer both for header and body.
    411 
    412   // Convert the request to UTF-8 encoding.
    413   v8::String::Utf8Value utf8_request(request);
    414 
    415   // Send the header.
    416   int len;
    417   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
    418                      "Content-Length: %d\r\n", utf8_request.length());
    419   conn->Send(buffer, len);
    420 
    421   // Terminate header with empty line.
    422   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
    423   conn->Send(buffer, len);
    424 
    425   // Send message body as UTF-8.
    426   conn->Send(*utf8_request, utf8_request.length());
    427 
    428   return true;
    429 }
    430 
    431 
    432 // Receive the full buffer before returning unless an error occours.
    433 int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
    434   int total_received = 0;
    435   while (total_received < len) {
    436     int received = conn->Receive(data + total_received, len - total_received);
    437     if (received <= 0) {
    438       return total_received;
    439     }
    440     total_received += received;
    441   }
    442   return total_received;
    443 }
    444 
    445 } }  // namespace v8::internal
    446 
    447 #endif  // ENABLE_DEBUGGER_SUPPORT
    448