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
33namespace v8 {
34namespace internal {
35
36// Public V8 debugger API message handler function. This function just delegates
37// to the debugger agent through it's data parameter.
38void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
39  DebuggerAgent::instance_->DebuggerMessage(message);
40}
41
42// static
43DebuggerAgent* DebuggerAgent::instance_ = NULL;
44
45// Debugger agent main thread.
46void 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
84void 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
99void DebuggerAgent::WaitUntilListening() {
100  listening_->Wait();
101}
102
103void 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
122void 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
135void 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
147void 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
162void 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
197void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
198  DebuggerAgentUtil::SendMessage(client_, message);
199}
200
201
202void DebuggerAgentSession::Shutdown() {
203  // Shutdown the socket to end the blocking receive.
204  client_->Shutdown();
205}
206
207
208const char* DebuggerAgentUtil::kContentLength = "Content-Length";
209int DebuggerAgentUtil::kContentLengthSize =
210    StrLength(kContentLength);
211
212
213SmartPointer<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
301bool 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
347bool 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
387bool 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.
413int 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