1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2009 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h" 30086aeeaae12517475c22695a200be45495516549Ben Murdoch#include "debug.h" 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "debug-agent.h" 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_DEBUGGER_SUPPORT 34086aeeaae12517475c22695a200be45495516549Ben Murdoch 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 { 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal { 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Public V8 debugger API message handler function. This function just delegates 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// to the debugger agent through it's data parameter. 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgentMessageHandler(const v8::Debug::Message& message) { 4144f0eee88ff00398ff7f715fab053374d808c90dSteve Block DebuggerAgent* agent = Isolate::Current()->debugger_agent_instance(); 4244f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(agent != NULL); 4344f0eee88ff00398ff7f715fab053374d808c90dSteve Block agent->DebuggerMessage(message); 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Debugger agent main thread. 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgent::Run() { 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int kOneSecondInMicros = 1000000; 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allow this socket to reuse port even if still in TIME_WAIT. 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block server_->SetReuseAddress(true); 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // First bind the socket to the requested port. 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool bound = false; 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (!bound && !terminate_) { 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bound = server_->Bind(port_); 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 59e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke // If an error occurred wait a bit before retrying. The most common error 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // would be that the port is already in use so this avoids a busy loop and 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // make the agent take over the port when it becomes free. 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!bound) { 63e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke PrintF("Failed to open socket on port %d, " 64e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke "waiting %d ms before retrying\n", port_, kOneSecondInMicros / 1000); 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block terminate_now_->Wait(kOneSecondInMicros); 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Accept connections on the bound port. 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (!terminate_) { 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool ok = server_->Listen(1); 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block listening_->Signal(); 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ok) { 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Accept the new connection. 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Socket* client = server_->Accept(); 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ok = client != NULL; 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (ok) { 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Create and start a new session. 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CreateSession(client); 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgent::Shutdown() { 87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Set the termination flag. 88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block terminate_ = true; 89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Signal termination and make the server exit either its listen call or its 91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // binding loop. This makes sure that no new sessions can be established. 92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block terminate_now_->Signal(); 93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block server_->Shutdown(); 94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Join(); 95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Close existing session if any. 97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CloseSession(); 98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgent::WaitUntilListening() { 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block listening_->Wait(); 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic const char* kCreateSessionMessage = 10644f0eee88ff00398ff7f715fab053374d808c90dSteve Block "Remote debugging session already active\r\n"; 10744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgent::CreateSession(Socket* client) { 109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ScopedLock with(session_access_); 110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If another session is already established terminate this one. 112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (session_ != NULL) { 11344f0eee88ff00398ff7f715fab053374d808c90dSteve Block client->Send(kCreateSessionMessage, StrLength(kCreateSessionMessage)); 114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block delete client; 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Create a new session and hook up the debug message handler. 1193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch session_ = new DebuggerAgentSession(this, client); 1203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch isolate_->debugger()->SetMessageHandler(DebuggerAgentMessageHandler); 121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block session_->Start(); 122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgent::CloseSession() { 126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ScopedLock with(session_access_); 127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Terminate the session. 129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (session_ != NULL) { 130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block session_->Shutdown(); 131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block session_->Join(); 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block delete session_; 133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block session_ = NULL; 134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) { 139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ScopedLock with(session_access_); 140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Forward the message handling to the session. 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (session_ != NULL) { 143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::String::Value val(message.GetJSON()); 144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(*val), 145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block val.length())); 146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) { 151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Don't do anything during termination. 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (terminate_) { 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Terminate the session. 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ScopedLock with(session_access_); 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(session == session_); 159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (session == session_) { 160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CloseSession(); 161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgentSession::Run() { 166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send the hello message. 167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_); 168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ok) return; 169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (true) { 171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Read data from the debugger front end. 172589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch SmartArrayPointer<char> message = 173589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch DebuggerAgentUtil::ReceiveMessage(client_); 174086aeeaae12517475c22695a200be45495516549Ben Murdoch 175086aeeaae12517475c22695a200be45495516549Ben Murdoch const char* msg = *message; 176086aeeaae12517475c22695a200be45495516549Ben Murdoch bool is_closing_session = (msg == NULL); 177086aeeaae12517475c22695a200be45495516549Ben Murdoch 178086aeeaae12517475c22695a200be45495516549Ben Murdoch if (msg == NULL) { 179086aeeaae12517475c22695a200be45495516549Ben Murdoch // If we lost the connection, then simulate a disconnect msg: 180086aeeaae12517475c22695a200be45495516549Ben Murdoch msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}"; 181086aeeaae12517475c22695a200be45495516549Ben Murdoch 182086aeeaae12517475c22695a200be45495516549Ben Murdoch } else { 183086aeeaae12517475c22695a200be45495516549Ben Murdoch // Check if we're getting a disconnect request: 184086aeeaae12517475c22695a200be45495516549Ben Murdoch const char* disconnectRequestStr = 185086aeeaae12517475c22695a200be45495516549Ben Murdoch "\"type\":\"request\",\"command\":\"disconnect\"}"; 186086aeeaae12517475c22695a200be45495516549Ben Murdoch const char* result = strstr(msg, disconnectRequestStr); 187086aeeaae12517475c22695a200be45495516549Ben Murdoch if (result != NULL) { 188086aeeaae12517475c22695a200be45495516549Ben Murdoch is_closing_session = true; 189086aeeaae12517475c22695a200be45495516549Ben Murdoch } 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Convert UTF-8 to UTF-16. 193086aeeaae12517475c22695a200be45495516549Ben Murdoch unibrow::Utf8InputBuffer<> buf(msg, StrLength(msg)); 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int len = 0; 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (buf.has_more()) { 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block buf.GetNext(); 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len++; 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 19925f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen ScopedVector<int16_t> temp(len + 1); 200086aeeaae12517475c22695a200be45495516549Ben Murdoch buf.Reset(msg, StrLength(msg)); 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < len; i++) { 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block temp[i] = buf.GetNext(); 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send the request received to the debugger. 20625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp.start()), 2073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch len, 2083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch NULL, 2093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch reinterpret_cast<v8::Isolate*>(agent_->isolate())); 210086aeeaae12517475c22695a200be45495516549Ben Murdoch 211086aeeaae12517475c22695a200be45495516549Ben Murdoch if (is_closing_session) { 212086aeeaae12517475c22695a200be45495516549Ben Murdoch // Session is closed. 213086aeeaae12517475c22695a200be45495516549Ben Murdoch agent_->OnSessionClosed(this); 214086aeeaae12517475c22695a200be45495516549Ben Murdoch return; 215086aeeaae12517475c22695a200be45495516549Ben Murdoch } 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) { 221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block DebuggerAgentUtil::SendMessage(client_, message); 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid DebuggerAgentSession::Shutdown() { 226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Shutdown the socket to end the blocking receive. 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block client_->Shutdown(); 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 23144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockconst char* const DebuggerAgentUtil::kContentLength = "Content-Length"; 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 234589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben MurdochSmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) { 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int received; 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Read header. 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int content_length = 0; 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (true) { 240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int kHeaderBufferSize = 80; 241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char header_buffer[kHeaderBufferSize]; 242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int header_buffer_position = 0; 243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char c = '\0'; // One character receive buffer. 244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char prev_c = '\0'; // Previous character. 245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Read until CRLF. 247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (!(c == '\n' && prev_c == '\r')) { 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block prev_c = c; 249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block received = conn->Receive(&c, 1); 250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (received <= 0) { 251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PrintF("Error %d\n", Socket::LastError()); 252589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return SmartArrayPointer<char>(); 253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add character to header buffer. 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (header_buffer_position < kHeaderBufferSize) { 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block header_buffer[header_buffer_position++] = c; 258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check for end of header (empty header line). 262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (header_buffer_position == 2) { // Receive buffer contains CRLF. 263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Terminate header. 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(header_buffer_position > 1); // At least CRLF is received. 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(header_buffer_position <= kHeaderBufferSize); 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block header_buffer[header_buffer_position - 2] = '\0'; 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Split header. 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* key = header_buffer; 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* value = NULL; 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; header_buffer[i] != '\0'; i++) { 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (header_buffer[i] == ':') { 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block header_buffer[i] = '\0'; 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value = header_buffer + i + 1; 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (*value == ' ') { 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block value++; 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block break; 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that key is Content-Length. 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (strcmp(key, kContentLength) == 0) { 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the content length value if present and within a sensible range. 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (value == NULL || strlen(value) > 7) { 289589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return SmartArrayPointer<char>(); 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; value[i] != '\0'; i++) { 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Bail out if illegal data. 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (value[i] < '0' || value[i] > '9') { 294589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return SmartArrayPointer<char>(); 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block content_length = 10 * content_length + (value[i] - '0'); 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // For now just print all other headers than Content-Length. 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PrintF("%s: %s\n", key, value != NULL ? value : "(no value)"); 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return now if no body. 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (content_length == 0) { 306589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return SmartArrayPointer<char>(); 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Read body. 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* buffer = NewArray<char>(content_length + 1); 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block received = ReceiveAll(conn, buffer, content_length); 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (received < content_length) { 313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PrintF("Error %d\n", Socket::LastError()); 314589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return SmartArrayPointer<char>(); 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block buffer[content_length] = '\0'; 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 318589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return SmartArrayPointer<char>(buffer); 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool DebuggerAgentUtil::SendConnectMessage(const Socket* conn, 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* embedding_host) { 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kBufferSize = 80; 325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char buffer[kBufferSize]; // Sending buffer. 326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool ok; 327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int len; 328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send the header. 330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), 331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Type: connect\r\n"); 332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ok = conn->Send(buffer, len); 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ok) return false; 334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), 336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "V8-Version: %s\r\n", v8::V8::GetVersion()); 337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ok = conn->Send(buffer, len); 338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ok) return false; 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), 341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Protocol-Version: 1\r\n"); 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ok = conn->Send(buffer, len); 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ok) return false; 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (embedding_host != NULL) { 346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Embedding-Host: %s\r\n", embedding_host); 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ok = conn->Send(buffer, len); 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ok) return false; 350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), 353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "%s: 0\r\n", kContentLength); 354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ok = conn->Send(buffer, len); 355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ok) return false; 356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Terminate header with empty line. 358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n"); 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ok = conn->Send(buffer, len); 360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!ok) return false; 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // No body for connect message. 363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool DebuggerAgentUtil::SendMessage(const Socket* conn, 369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const Vector<uint16_t> message) { 370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kBufferSize = 80; 371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char buffer[kBufferSize]; // Sending buffer both for header and body. 372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Calculate the message size in UTF-8 encoding. 374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int utf8_len = 0; 3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int previous = unibrow::Utf16::kNoPreviousCharacter; 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < message.length(); i++) { 3773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint16_t character = message[i]; 3783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch utf8_len += unibrow::Utf8::Length(character, previous); 3793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch previous = character; 380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send the header. 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int len; 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), 385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "%s: %d\r\n", kContentLength, utf8_len); 386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block conn->Send(buffer, len); 387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Terminate header with empty line. 389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n"); 390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block conn->Send(buffer, len); 391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send message body as UTF-8. 393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int buffer_position = 0; // Current buffer position. 3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch previous = unibrow::Utf16::kNoPreviousCharacter; 395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < message.length(); i++) { 396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Write next UTF-8 encoded character to buffer. 3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint16_t character = message[i]; 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block buffer_position += 3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch unibrow::Utf8::Encode(buffer + buffer_position, character, previous); 400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(buffer_position < kBufferSize); 401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send buffer if full or last character is encoded. 4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (kBufferSize - buffer_position < 4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit || 4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch i == message.length() - 1) { 4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (unibrow::Utf16::IsLeadSurrogate(character)) { 4073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kEncodedSurrogateLength = 4083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch unibrow::Utf16::kUtf8BytesToCodeASurrogate; 4093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(buffer_position >= kEncodedSurrogateLength); 4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch conn->Send(buffer, buffer_position - kEncodedSurrogateLength); 4113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < kEncodedSurrogateLength; i++) { 4123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch buffer[i] = buffer[buffer_position + i]; 4133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 4143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch buffer_position = kEncodedSurrogateLength; 4153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else { 4163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch conn->Send(buffer, buffer_position); 4173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch buffer_position = 0; 4183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch previous = character; 421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool DebuggerAgentUtil::SendMessage(const Socket* conn, 428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const v8::Handle<v8::String> request) { 429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block static const int kBufferSize = 80; 430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char buffer[kBufferSize]; // Sending buffer both for header and body. 431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Convert the request to UTF-8 encoding. 433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block v8::String::Utf8Value utf8_request(request); 434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send the header. 436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int len; 437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), 438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "Content-Length: %d\r\n", utf8_request.length()); 439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block conn->Send(buffer, len); 440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Terminate header with empty line. 442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n"); 443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block conn->Send(buffer, len); 444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Send message body as UTF-8. 446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block conn->Send(*utf8_request, utf8_request.length()); 447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Receive the full buffer before returning unless an error occours. 453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) { 454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int total_received = 0; 455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (total_received < len) { 456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int received = conn->Receive(data + total_received, len - total_received); 457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (received <= 0) { 458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return total_received; 459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block total_received += received; 461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return total_received; 463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} } // namespace v8::internal 466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif // ENABLE_DEBUGGER_SUPPORT 468