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