• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
DebuggerAgentMessageHandler(const v8::Debug::Message & message)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.
Run()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 
Shutdown()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 
WaitUntilListening()101 void DebuggerAgent::WaitUntilListening() {
102   listening_->Wait();
103 }
104 
105 static const char* kCreateSessionMessage =
106     "Remote debugging session already active\r\n";
107 
CreateSession(Socket * client)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(this, client);
120   isolate_->debugger()->SetMessageHandler(DebuggerAgentMessageHandler);
121   session_->Start();
122 }
123 
124 
CloseSession()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 
DebuggerMessage(const v8::Debug::Message & message)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 
OnSessionClosed(DebuggerAgentSession * session)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 
Run()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     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 
DebuggerMessage(Vector<uint16_t> message)220 void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
221   DebuggerAgentUtil::SendMessage(client_, message);
222 }
223 
224 
Shutdown()225 void DebuggerAgentSession::Shutdown() {
226   // Shutdown the socket to end the blocking receive.
227   client_->Shutdown();
228 }
229 
230 
231 const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
232 
233 
ReceiveMessage(const Socket * conn)234 SmartArrayPointer<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 
SendConnectMessage(const Socket * conn,const char * embedding_host)322 bool 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 
SendMessage(const Socket * conn,const Vector<uint16_t> message)368 bool 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 
SendMessage(const Socket * conn,const v8::Handle<v8::String> request)427 bool 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.
ReceiveAll(const Socket * conn,char * data,int len)453 int 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