Index: chrome/browser/devtools/adb_client_socket.cc |
diff --git a/chrome/browser/devtools/adb_client_socket.cc b/chrome/browser/devtools/adb_client_socket.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..df1c258f34d52b9505d7834ded7ad02b52ddc0b1 |
--- /dev/null |
+++ b/chrome/browser/devtools/adb_client_socket.cc |
@@ -0,0 +1,161 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/devtools/adb_client_socket.h" |
+ |
+#include "base/bind.h" |
+#include "base/compiler_specific.h" |
+#include "base/stringprintf.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "net/base/net_errors.h" |
+ |
+namespace { |
+ |
+const int kBufferSize = 16 * 1024; |
+ |
+std::string EncodeLength(size_t length) { |
+ static const char kHexChars[] = "0123456789ABCDEF"; |
+ |
+ std::string result(4, '\0'); |
+ char b = reinterpret_cast<const char*>(&length)[1]; |
+ result[0] = kHexChars[(b >> 4) & 0xf]; |
+ result[1] = kHexChars[b & 0xf]; |
+ b = reinterpret_cast<const char*>(&length)[0]; |
+ result[2] = kHexChars[(b >> 4) & 0xf]; |
+ result[3] = kHexChars[b & 0xf]; |
+ return result; |
+} |
+ |
+} // namespace |
+ |
+// static |
+void ADBClientSocket::Query(int port, |
+ const std::string& query, |
+ const Callback& callback) { |
+ (new ADBClientSocket())->InnerQuery(port, query, callback); |
+} |
+ |
+ADBClientSocket::ADBClientSocket() : expected_response_length_(-1) { |
+} |
+ |
+ADBClientSocket::~ADBClientSocket() { |
+} |
+ |
+void ADBClientSocket::InnerQuery(int port, |
+ const std::string& query, |
+ const Callback& callback) { |
+ if (query.length() > 0xFFFF) { |
+ ReportErrorAndDie("Input message is too big"); |
+ return; |
+ } |
+ callback_ = callback; |
+ |
+ net::IPAddressNumber ip_number; |
+ if (!net::ParseIPLiteralToNumber("127.0.0.1", &ip_number)) { |
+ ReportErrorAndDie("Could not connect to ADB"); |
+ return; |
+ } |
+ |
+ net::AddressList address_list = |
+ net::AddressList::CreateFromIPAddress(ip_number, port); |
+ socket_.reset(new net::TCPClientSocket(address_list, NULL, |
+ net::NetLog::Source())); |
+ std::string message = EncodeLength(query.length()) + query; |
+ scoped_refptr<net::StringIOBuffer> request_buffer = |
+ new net::StringIOBuffer(message); |
+ int result = socket_->Connect(base::Bind(&ADBClientSocket::OnConnectComplete, |
+ base::Unretained(this), |
+ request_buffer)); |
+ if (result != net::ERR_IO_PENDING) |
+ ReportErrorAndDie("Could not connect to ADB"); |
+} |
+ |
+void ADBClientSocket::OnConnectComplete( |
+ scoped_refptr<net::StringIOBuffer> request_buffer, |
+ int result) { |
+ if (!CheckNetResultOrDie(result)) |
+ return; |
+ result = socket_->Write(request_buffer, request_buffer->size(), |
+ base::Bind(&ADBClientSocket::OnWriteComplete, base::Unretained(this))); |
+ if (result != net::ERR_IO_PENDING) |
+ OnWriteComplete(result); |
+} |
+ |
+void ADBClientSocket::OnWriteComplete(int result) { |
+ if (!CheckNetResultOrDie(result)) |
+ return; |
+ scoped_refptr<net::IOBuffer> response_buffer = |
+ new net::IOBuffer(kBufferSize); |
+ result = socket_->Read(response_buffer, kBufferSize, |
+ base::Bind(&ADBClientSocket::OnReadComplete, base::Unretained(this), |
+ response_buffer)); |
+ if (result != net::ERR_IO_PENDING) |
+ OnReadComplete(response_buffer, result); |
+} |
+ |
+void ADBClientSocket::OnReadComplete( |
+ scoped_refptr<net::IOBuffer> response_buffer, |
+ int result) { |
+ if (!CheckNetResultOrDie(result)) |
+ return; |
+ |
+ response_ += std::string(response_buffer->data(), result); |
+ if (expected_response_length_ == -1) { |
+ // Reading header |
+ if (result < 8) { |
+ ReportErrorAndDie("Response is too short: " + response_); |
+ return; |
+ } |
+ |
+ std::string status = response_.substr(0, 4); |
+ if (status != "OKAY" && status != "FAIL") { |
+ ReportInvalidResponseAndDie(); |
+ return; |
+ } |
+ std::string payload_length = response_.substr(4, 4); |
+ if (!base::HexStringToInt(response_.substr(4, 4), |
+ &expected_response_length_)) { |
+ ReportInvalidResponseAndDie(); |
+ return; |
+ } |
+ } |
+ |
+ if (static_cast<int>(response_.length() - 8) == expected_response_length_) { |
+ ReportSuccessAndDie(); |
+ return; |
+ } |
+ |
+ // Read tail |
+ result = socket_->Read(response_buffer, kBufferSize, |
+ base::Bind(&ADBClientSocket::OnReadComplete, base::Unretained(this), |
+ response_buffer)); |
+ if (result != net::ERR_IO_PENDING) |
+ OnReadComplete(response_buffer, result); |
+} |
+ |
+bool ADBClientSocket::CheckNetResultOrDie(int result) { |
+ if (result >= 0) |
+ return true; |
+ ReportErrorAndDie(base::StringPrintf("Internal error %d", result)); |
+ return false; |
+} |
+ |
+void ADBClientSocket::ReportSuccessAndDie() { |
+ callback_.Run(std::string(), response_.substr(8)); |
+ Destroy(); |
+} |
+ |
+void ADBClientSocket::ReportInvalidResponseAndDie() { |
+ callback_.Run("Invalid response: " + response_, std::string()); |
+ Destroy(); |
+} |
+ |
+void ADBClientSocket::ReportErrorAndDie(const std::string& error) { |
+ callback_.Run(error, std::string()); |
+ Destroy(); |
+} |
+ |
+void ADBClientSocket::Destroy() { |
+ delete this; |
+} |