Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / browser / devtools / device / adb / adb_client_socket.cc
blob41b3c9bed471fec8df79856ee034c20ebdd4fc84
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/devtools/device/adb/adb_client_socket.h"
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/net_util.h"
14 #include "net/socket/tcp_client_socket.h"
16 namespace {
18 const int kBufferSize = 16 * 1024;
19 const char kOkayResponse[] = "OKAY";
20 const char kHostTransportCommand[] = "host:transport:%s";
21 const char kLocalhost[] = "127.0.0.1";
23 std::string EncodeMessage(const std::string& message) {
24 static const char kHexChars[] = "0123456789ABCDEF";
26 size_t length = message.length();
27 std::string result(4, '\0');
28 char b = reinterpret_cast<const char*>(&length)[1];
29 result[0] = kHexChars[(b >> 4) & 0xf];
30 result[1] = kHexChars[b & 0xf];
31 b = reinterpret_cast<const char*>(&length)[0];
32 result[2] = kHexChars[(b >> 4) & 0xf];
33 result[3] = kHexChars[b & 0xf];
34 return result + message;
37 class AdbTransportSocket : public AdbClientSocket {
38 public:
39 AdbTransportSocket(int port,
40 const std::string& serial,
41 const std::string& socket_name,
42 const SocketCallback& callback)
43 : AdbClientSocket(port),
44 serial_(serial),
45 socket_name_(socket_name),
46 callback_(callback) {
47 Connect(base::Bind(&AdbTransportSocket::OnConnected,
48 base::Unretained(this)));
51 private:
52 ~AdbTransportSocket() {}
54 void OnConnected(int result) {
55 if (!CheckNetResultOrDie(result))
56 return;
57 SendCommand(base::StringPrintf(kHostTransportCommand, serial_.c_str()),
58 true, base::Bind(&AdbTransportSocket::SendLocalAbstract,
59 base::Unretained(this)));
62 void SendLocalAbstract(int result, const std::string& response) {
63 if (!CheckNetResultOrDie(result))
64 return;
65 SendCommand(socket_name_, true,
66 base::Bind(&AdbTransportSocket::OnSocketAvailable,
67 base::Unretained(this)));
70 void OnSocketAvailable(int result, const std::string& response) {
71 if (!CheckNetResultOrDie(result))
72 return;
73 callback_.Run(net::OK, socket_.Pass());
74 delete this;
77 bool CheckNetResultOrDie(int result) {
78 if (result >= 0)
79 return true;
80 callback_.Run(result, make_scoped_ptr<net::StreamSocket>(NULL));
81 delete this;
82 return false;
85 std::string serial_;
86 std::string socket_name_;
87 SocketCallback callback_;
90 class AdbQuerySocket : AdbClientSocket {
91 public:
92 AdbQuerySocket(int port,
93 const std::string& query,
94 const CommandCallback& callback)
95 : AdbClientSocket(port),
96 current_query_(0),
97 callback_(callback) {
98 if (Tokenize(query, "|", &queries_) == 0) {
99 CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT);
100 return;
102 Connect(base::Bind(&AdbQuerySocket::SendNextQuery,
103 base::Unretained(this)));
106 private:
107 ~AdbQuerySocket() {
110 void SendNextQuery(int result) {
111 if (!CheckNetResultOrDie(result))
112 return;
113 std::string query = queries_[current_query_];
114 if (query.length() > 0xFFFF) {
115 CheckNetResultOrDie(net::ERR_MSG_TOO_BIG);
116 return;
118 bool is_void = current_query_ < queries_.size() - 1;
119 SendCommand(query, is_void,
120 base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
123 void OnResponse(int result, const std::string& response) {
124 if (++current_query_ < queries_.size()) {
125 SendNextQuery(net::OK);
126 } else {
127 callback_.Run(result, response);
128 delete this;
132 bool CheckNetResultOrDie(int result) {
133 if (result >= 0)
134 return true;
135 callback_.Run(result, std::string());
136 delete this;
137 return false;
140 std::vector<std::string> queries_;
141 size_t current_query_;
142 CommandCallback callback_;
145 } // namespace
147 // static
148 void AdbClientSocket::AdbQuery(int port,
149 const std::string& query,
150 const CommandCallback& callback) {
151 new AdbQuerySocket(port, query, callback);
154 // static
155 void AdbClientSocket::TransportQuery(int port,
156 const std::string& serial,
157 const std::string& socket_name,
158 const SocketCallback& callback) {
159 new AdbTransportSocket(port, serial, socket_name, callback);
162 AdbClientSocket::AdbClientSocket(int port)
163 : host_(kLocalhost), port_(port) {
166 AdbClientSocket::~AdbClientSocket() {
169 void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
170 net::IPAddressNumber ip_number;
171 if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
172 callback.Run(net::ERR_FAILED);
173 return;
176 net::AddressList address_list =
177 net::AddressList::CreateFromIPAddress(ip_number, port_);
178 socket_.reset(new net::TCPClientSocket(address_list, NULL,
179 net::NetLog::Source()));
180 int result = socket_->Connect(callback);
181 if (result != net::ERR_IO_PENDING)
182 callback.Run(result);
185 void AdbClientSocket::SendCommand(const std::string& command,
186 bool is_void,
187 const CommandCallback& callback) {
188 scoped_refptr<net::StringIOBuffer> request_buffer =
189 new net::StringIOBuffer(EncodeMessage(command));
190 int result = socket_->Write(request_buffer.get(),
191 request_buffer->size(),
192 base::Bind(&AdbClientSocket::ReadResponse,
193 base::Unretained(this),
194 callback,
195 is_void));
196 if (result != net::ERR_IO_PENDING)
197 ReadResponse(callback, is_void, result);
200 void AdbClientSocket::ReadResponse(const CommandCallback& callback,
201 bool is_void,
202 int result) {
203 if (result < 0) {
204 callback.Run(result, "IO error");
205 return;
207 scoped_refptr<net::IOBuffer> response_buffer =
208 new net::IOBuffer(kBufferSize);
209 result = socket_->Read(response_buffer.get(),
210 kBufferSize,
211 base::Bind(&AdbClientSocket::OnResponseHeader,
212 base::Unretained(this),
213 callback,
214 is_void,
215 response_buffer));
216 if (result != net::ERR_IO_PENDING)
217 OnResponseHeader(callback, is_void, response_buffer, result);
220 void AdbClientSocket::OnResponseHeader(
221 const CommandCallback& callback,
222 bool is_void,
223 scoped_refptr<net::IOBuffer> response_buffer,
224 int result) {
225 if (result <= 0) {
226 callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
227 "IO error");
228 return;
231 std::string data = std::string(response_buffer->data(), result);
232 if (result < 4) {
233 callback.Run(net::ERR_FAILED, "Response is too short: " + data);
234 return;
237 std::string status = data.substr(0, 4);
238 if (status != kOkayResponse) {
239 callback.Run(net::ERR_FAILED, data);
240 return;
243 data = data.substr(4);
245 if (!is_void) {
246 int payload_length = 0;
247 int bytes_left = -1;
248 if (data.length() >= 4 &&
249 base::HexStringToInt(data.substr(0, 4), &payload_length)) {
250 data = data.substr(4);
251 bytes_left = payload_length - result + 8;
252 } else {
253 bytes_left = -1;
255 OnResponseData(callback, data, response_buffer, bytes_left, 0);
256 } else {
257 callback.Run(net::OK, data);
261 void AdbClientSocket::OnResponseData(
262 const CommandCallback& callback,
263 const std::string& response,
264 scoped_refptr<net::IOBuffer> response_buffer,
265 int bytes_left,
266 int result) {
267 if (result < 0) {
268 callback.Run(result, "IO error");
269 return;
272 bytes_left -= result;
273 std::string new_response =
274 response + std::string(response_buffer->data(), result);
275 if (bytes_left == 0) {
276 callback.Run(net::OK, new_response);
277 return;
280 // Read tail
281 result = socket_->Read(response_buffer.get(),
282 kBufferSize,
283 base::Bind(&AdbClientSocket::OnResponseData,
284 base::Unretained(this),
285 callback,
286 new_response,
287 response_buffer,
288 bytes_left));
289 if (result > 0)
290 OnResponseData(callback, new_response, response_buffer, bytes_left, result);
291 else if (result != net::ERR_IO_PENDING)
292 callback.Run(net::OK, new_response);