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