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
35namespace v8 {
36namespace internal {
37
38// Public V8 debugger API message handler function. This function just delegates
39// to the debugger agent through it's data parameter.
40void 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.
48void 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
86void 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
101void DebuggerAgent::WaitUntilListening() {
102  listening_->Wait();
103}
104
105static const char* kCreateSessionMessage =
106    "Remote debugging session already active\r\n";
107
108void 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
125void 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
138void 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
150void 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
165void 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
220void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
221  DebuggerAgentUtil::SendMessage(client_, message);
222}
223
224
225void DebuggerAgentSession::Shutdown() {
226  // Shutdown the socket to end the blocking receive.
227  client_->Shutdown();
228}
229
230
231const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
232
233
234SmartArrayPointer<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
322bool 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
368bool 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
427bool 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.
453int 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