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