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
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  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
48DebuggerAgent::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
63DebuggerAgent::~DebuggerAgent() {
64  isolate_->set_debugger_agent_instance(NULL);
65  delete server_;
66}
67
68
69// Debugger agent main thread.
70void 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
110void 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
125void DebuggerAgent::WaitUntilListening() {
126  listening_.Wait();
127}
128
129static const char* kCreateSessionMessage =
130    "Remote debugging session already active\r\n";
131
132void 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
151void 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
164void 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
176void 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
193void 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
241void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
242  DebuggerAgentUtil::SendMessage(client_, message);
243}
244
245
246void DebuggerAgentSession::Shutdown() {
247  // Shutdown the socket to end the blocking receive.
248  client_->Shutdown();
249}
250
251
252const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
253
254
255SmartArrayPointer<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
343bool 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
389bool 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
457bool 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.
489int 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