• 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(isolate(), this, client);
120   v8::Debug::SetMessageHandler2(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     SmartPointer<char> message = DebuggerAgentUtil::ReceiveMessage(client_);
173 
174     const char* msg = *message;
175     bool is_closing_session = (msg == NULL);
176 
177     if (msg == NULL) {
178       // If we lost the connection, then simulate a disconnect msg:
179       msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}";
180 
181     } else {
182       // Check if we're getting a disconnect request:
183       const char* disconnectRequestStr =
184           "\"type\":\"request\",\"command\":\"disconnect\"}";
185       const char* result = strstr(msg, disconnectRequestStr);
186       if (result != NULL) {
187         is_closing_session = true;
188       }
189     }
190 
191     // Convert UTF-8 to UTF-16.
192     unibrow::Utf8InputBuffer<> buf(msg, StrLength(msg));
193     int len = 0;
194     while (buf.has_more()) {
195       buf.GetNext();
196       len++;
197     }
198     ScopedVector<int16_t> temp(len + 1);
199     buf.Reset(msg, StrLength(msg));
200     for (int i = 0; i < len; i++) {
201       temp[i] = buf.GetNext();
202     }
203 
204     // Send the request received to the debugger.
205     v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp.start()),
206                            len);
207 
208     if (is_closing_session) {
209       // Session is closed.
210       agent_->OnSessionClosed(this);
211       return;
212     }
213   }
214 }
215 
216 
DebuggerMessage(Vector<uint16_t> message)217 void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
218   DebuggerAgentUtil::SendMessage(client_, message);
219 }
220 
221 
Shutdown()222 void DebuggerAgentSession::Shutdown() {
223   // Shutdown the socket to end the blocking receive.
224   client_->Shutdown();
225 }
226 
227 
228 const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
229 const int DebuggerAgentUtil::kContentLengthSize =
230     StrLength(kContentLength);
231 
232 
ReceiveMessage(const Socket * conn)233 SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
234   int received;
235 
236   // Read header.
237   int content_length = 0;
238   while (true) {
239     const int kHeaderBufferSize = 80;
240     char header_buffer[kHeaderBufferSize];
241     int header_buffer_position = 0;
242     char c = '\0';  // One character receive buffer.
243     char prev_c = '\0';  // Previous character.
244 
245     // Read until CRLF.
246     while (!(c == '\n' && prev_c == '\r')) {
247       prev_c = c;
248       received = conn->Receive(&c, 1);
249       if (received <= 0) {
250         PrintF("Error %d\n", Socket::LastError());
251         return SmartPointer<char>();
252       }
253 
254       // Add character to header buffer.
255       if (header_buffer_position < kHeaderBufferSize) {
256         header_buffer[header_buffer_position++] = c;
257       }
258     }
259 
260     // Check for end of header (empty header line).
261     if (header_buffer_position == 2) {  // Receive buffer contains CRLF.
262       break;
263     }
264 
265     // Terminate header.
266     ASSERT(header_buffer_position > 1);  // At least CRLF is received.
267     ASSERT(header_buffer_position <= kHeaderBufferSize);
268     header_buffer[header_buffer_position - 2] = '\0';
269 
270     // Split header.
271     char* key = header_buffer;
272     char* value = NULL;
273     for (int i = 0; header_buffer[i] != '\0'; i++) {
274       if (header_buffer[i] == ':') {
275         header_buffer[i] = '\0';
276         value = header_buffer + i + 1;
277         while (*value == ' ') {
278           value++;
279         }
280         break;
281       }
282     }
283 
284     // Check that key is Content-Length.
285     if (strcmp(key, kContentLength) == 0) {
286       // Get the content length value if present and within a sensible range.
287       if (value == NULL || strlen(value) > 7) {
288         return SmartPointer<char>();
289       }
290       for (int i = 0; value[i] != '\0'; i++) {
291         // Bail out if illegal data.
292         if (value[i] < '0' || value[i] > '9') {
293           return SmartPointer<char>();
294         }
295         content_length = 10 * content_length + (value[i] - '0');
296       }
297     } else {
298       // For now just print all other headers than Content-Length.
299       PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
300     }
301   }
302 
303   // Return now if no body.
304   if (content_length == 0) {
305     return SmartPointer<char>();
306   }
307 
308   // Read body.
309   char* buffer = NewArray<char>(content_length + 1);
310   received = ReceiveAll(conn, buffer, content_length);
311   if (received < content_length) {
312     PrintF("Error %d\n", Socket::LastError());
313     return SmartPointer<char>();
314   }
315   buffer[content_length] = '\0';
316 
317   return SmartPointer<char>(buffer);
318 }
319 
320 
SendConnectMessage(const Socket * conn,const char * embedding_host)321 bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
322                                            const char* embedding_host) {
323   static const int kBufferSize = 80;
324   char buffer[kBufferSize];  // Sending buffer.
325   bool ok;
326   int len;
327 
328   // Send the header.
329   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
330                      "Type: connect\r\n");
331   ok = conn->Send(buffer, len);
332   if (!ok) return false;
333 
334   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
335                      "V8-Version: %s\r\n", v8::V8::GetVersion());
336   ok = conn->Send(buffer, len);
337   if (!ok) return false;
338 
339   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
340                      "Protocol-Version: 1\r\n");
341   ok = conn->Send(buffer, len);
342   if (!ok) return false;
343 
344   if (embedding_host != NULL) {
345     len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
346                        "Embedding-Host: %s\r\n", embedding_host);
347     ok = conn->Send(buffer, len);
348     if (!ok) return false;
349   }
350 
351   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
352                      "%s: 0\r\n", kContentLength);
353   ok = conn->Send(buffer, len);
354   if (!ok) return false;
355 
356   // Terminate header with empty line.
357   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
358   ok = conn->Send(buffer, len);
359   if (!ok) return false;
360 
361   // No body for connect message.
362 
363   return true;
364 }
365 
366 
SendMessage(const Socket * conn,const Vector<uint16_t> message)367 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
368                                     const Vector<uint16_t> message) {
369   static const int kBufferSize = 80;
370   char buffer[kBufferSize];  // Sending buffer both for header and body.
371 
372   // Calculate the message size in UTF-8 encoding.
373   int utf8_len = 0;
374   for (int i = 0; i < message.length(); i++) {
375     utf8_len += unibrow::Utf8::Length(message[i]);
376   }
377 
378   // Send the header.
379   int len;
380   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
381                      "%s: %d\r\n", kContentLength, utf8_len);
382   conn->Send(buffer, len);
383 
384   // Terminate header with empty line.
385   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
386   conn->Send(buffer, len);
387 
388   // Send message body as UTF-8.
389   int buffer_position = 0;  // Current buffer position.
390   for (int i = 0; i < message.length(); i++) {
391     // Write next UTF-8 encoded character to buffer.
392     buffer_position +=
393         unibrow::Utf8::Encode(buffer + buffer_position, message[i]);
394     ASSERT(buffer_position < kBufferSize);
395 
396     // Send buffer if full or last character is encoded.
397     if (kBufferSize - buffer_position < 3 || i == message.length() - 1) {
398       conn->Send(buffer, buffer_position);
399       buffer_position = 0;
400     }
401   }
402 
403   return true;
404 }
405 
406 
SendMessage(const Socket * conn,const v8::Handle<v8::String> request)407 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
408                                     const v8::Handle<v8::String> request) {
409   static const int kBufferSize = 80;
410   char buffer[kBufferSize];  // Sending buffer both for header and body.
411 
412   // Convert the request to UTF-8 encoding.
413   v8::String::Utf8Value utf8_request(request);
414 
415   // Send the header.
416   int len;
417   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
418                      "Content-Length: %d\r\n", utf8_request.length());
419   conn->Send(buffer, len);
420 
421   // Terminate header with empty line.
422   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
423   conn->Send(buffer, len);
424 
425   // Send message body as UTF-8.
426   conn->Send(*utf8_request, utf8_request.length());
427 
428   return true;
429 }
430 
431 
432 // Receive the full buffer before returning unless an error occours.
ReceiveAll(const Socket * conn,char * data,int len)433 int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
434   int total_received = 0;
435   while (total_received < len) {
436     int received = conn->Receive(data + total_received, len - total_received);
437     if (received <= 0) {
438       return total_received;
439     }
440     total_received += received;
441   }
442   return total_received;
443 }
444 
445 } }  // namespace v8::internal
446 
447 #endif  // ENABLE_DEBUGGER_SUPPORT
448