1 // Copyright (c) 2013 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/adb_client_socket.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/address_list.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/net_util.h"
16 #include "net/socket/tcp_client_socket.h"
20 const int kBufferSize = 16 * 1024;
21 const char kOkayResponse[] = "OKAY";
22 const char kHostTransportCommand[] = "host:transport:%s";
23 const char kLocalhost[] = "127.0.0.1";
25 typedef base::Callback<void(int, const std::string&)> CommandCallback;
26 typedef base::Callback<void(int, net::StreamSocket*)> SocketCallback;
28 std::string EncodeMessage(const std::string& message) {
29 static const char kHexChars[] = "0123456789ABCDEF";
31 size_t length = message.length();
32 std::string result(4, '\0');
33 char b = reinterpret_cast<const char*>(&length)[1];
34 result[0] = kHexChars[(b >> 4) & 0xf];
35 result[1] = kHexChars[b & 0xf];
36 b = reinterpret_cast<const char*>(&length)[0];
37 result[2] = kHexChars[(b >> 4) & 0xf];
38 result[3] = kHexChars[b & 0xf];
39 return result + message;
42 class AdbTransportSocket : public AdbClientSocket {
44 AdbTransportSocket(int port,
45 const std::string& serial,
46 const std::string& socket_name,
47 const SocketCallback& callback)
48 : AdbClientSocket(port),
50 socket_name_(socket_name),
52 Connect(base::Bind(&AdbTransportSocket::OnConnected,
53 base::Unretained(this)));
57 ~AdbTransportSocket() {}
59 void OnConnected(int result) {
60 if (!CheckNetResultOrDie(result))
62 SendCommand(base::StringPrintf(kHostTransportCommand, serial_.c_str()),
63 true, base::Bind(&AdbTransportSocket::SendLocalAbstract,
64 base::Unretained(this)));
67 void SendLocalAbstract(int result, const std::string& response) {
68 if (!CheckNetResultOrDie(result))
70 SendCommand(socket_name_, true,
71 base::Bind(&AdbTransportSocket::OnSocketAvailable,
72 base::Unretained(this)));
75 void OnSocketAvailable(int result, const std::string& response) {
76 if (!CheckNetResultOrDie(result))
78 callback_.Run(net::OK, socket_.release());
82 bool CheckNetResultOrDie(int result) {
85 callback_.Run(result, NULL);
91 std::string socket_name_;
92 SocketCallback callback_;
95 class HttpOverAdbSocket {
97 HttpOverAdbSocket(net::StreamSocket* socket,
98 const std::string& request,
99 const CommandCallback& callback)
101 command_callback_(callback),
103 SendRequest(request);
106 HttpOverAdbSocket(net::StreamSocket* socket,
107 const std::string& request,
108 const SocketCallback& callback)
110 socket_callback_(callback),
112 SendRequest(request);
116 ~HttpOverAdbSocket() {
119 void SendRequest(const std::string& request) {
120 scoped_refptr<net::StringIOBuffer> request_buffer =
121 new net::StringIOBuffer(request);
123 int result = socket_->Write(
124 request_buffer.get(),
125 request_buffer->size(),
126 base::Bind(&HttpOverAdbSocket::ReadResponse, base::Unretained(this)));
127 if (result != net::ERR_IO_PENDING)
128 ReadResponse(result);
131 void ReadResponse(int result) {
132 if (!CheckNetResultOrDie(result))
134 scoped_refptr<net::IOBuffer> response_buffer =
135 new net::IOBuffer(kBufferSize);
137 result = socket_->Read(response_buffer.get(),
139 base::Bind(&HttpOverAdbSocket::OnResponseData,
140 base::Unretained(this),
143 if (result != net::ERR_IO_PENDING)
144 OnResponseData(response_buffer, -1, result);
147 void OnResponseData(scoped_refptr<net::IOBuffer> response_buffer,
150 if (!CheckNetResultOrDie(result))
153 CheckNetResultOrDie(net::ERR_CONNECTION_CLOSED);
157 response_ += std::string(response_buffer->data(), result);
158 int expected_length = 0;
159 if (bytes_total < 0) {
160 // TODO(kaznacheev): Use net::HttpResponseHeader to parse the header.
161 size_t content_pos = response_.find("Content-Length:");
162 if (content_pos != std::string::npos) {
163 size_t endline_pos = response_.find("\n", content_pos);
164 if (endline_pos != std::string::npos) {
165 std::string len = response_.substr(content_pos + 15,
166 endline_pos - content_pos - 15);
167 TrimWhitespace(len, TRIM_ALL, &len);
168 if (!base::StringToInt(len, &expected_length)) {
169 CheckNetResultOrDie(net::ERR_FAILED);
175 body_pos_ = response_.find("\r\n\r\n");
176 if (body_pos_ != std::string::npos) {
178 bytes_total = body_pos_ + expected_length;
182 if (bytes_total == static_cast<int>(response_.length())) {
183 if (!command_callback_.is_null())
184 command_callback_.Run(net::OK, response_.substr(body_pos_));
186 socket_callback_.Run(net::OK, socket_.release());
191 result = socket_->Read(response_buffer.get(),
193 base::Bind(&HttpOverAdbSocket::OnResponseData,
194 base::Unretained(this),
197 if (result != net::ERR_IO_PENDING)
198 OnResponseData(response_buffer, bytes_total, result);
201 bool CheckNetResultOrDie(int result) {
204 if (!command_callback_.is_null())
205 command_callback_.Run(result, std::string());
207 socket_callback_.Run(result, NULL);
212 scoped_ptr<net::StreamSocket> socket_;
213 std::string response_;
214 CommandCallback command_callback_;
215 SocketCallback socket_callback_;
219 class AdbQuerySocket : AdbClientSocket {
221 AdbQuerySocket(int port,
222 const std::string& query,
223 const CommandCallback& callback)
224 : AdbClientSocket(port),
226 callback_(callback) {
227 if (Tokenize(query, "|", &queries_) == 0) {
228 CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT);
231 Connect(base::Bind(&AdbQuerySocket::SendNextQuery,
232 base::Unretained(this)));
239 void SendNextQuery(int result) {
240 if (!CheckNetResultOrDie(result))
242 std::string query = queries_[current_query_];
243 if (query.length() > 0xFFFF) {
244 CheckNetResultOrDie(net::ERR_MSG_TOO_BIG);
247 bool is_void = current_query_ < queries_.size() - 1;
248 SendCommand(query, is_void,
249 base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
252 void OnResponse(int result, const std::string& response) {
253 if (++current_query_ < queries_.size()) {
254 SendNextQuery(net::OK);
256 callback_.Run(result, response);
261 bool CheckNetResultOrDie(int result) {
264 callback_.Run(result, std::string());
269 std::vector<std::string> queries_;
270 size_t current_query_;
271 CommandCallback callback_;
277 void AdbClientSocket::AdbQuery(int port,
278 const std::string& query,
279 const CommandCallback& callback) {
280 new AdbQuerySocket(port, query, callback);
283 #if defined(DEBUG_DEVTOOLS)
284 static void UseTransportQueryForDesktop(const SocketCallback& callback,
285 net::StreamSocket* socket,
287 callback.Run(result, socket);
289 #endif // defined(DEBUG_DEVTOOLS)
292 void AdbClientSocket::TransportQuery(int port,
293 const std::string& serial,
294 const std::string& socket_name,
295 const SocketCallback& callback) {
296 #if defined(DEBUG_DEVTOOLS)
297 if (serial.empty()) {
298 // Use plain socket for remote debugging on Desktop (debugging purposes).
299 net::IPAddressNumber ip_number;
300 net::ParseIPLiteralToNumber(kLocalhost, &ip_number);
303 if (!base::StringToInt(socket_name, &tcp_port))
306 net::AddressList address_list =
307 net::AddressList::CreateFromIPAddress(ip_number, tcp_port);
308 net::TCPClientSocket* socket = new net::TCPClientSocket(
309 address_list, NULL, net::NetLog::Source());
310 socket->Connect(base::Bind(&UseTransportQueryForDesktop, callback, socket));
313 #endif // defined(DEBUG_DEVTOOLS)
314 new AdbTransportSocket(port, serial, socket_name, callback);
318 void AdbClientSocket::HttpQuery(net::StreamSocket* socket,
319 const std::string& request_path,
320 const CommandCallback& callback) {
321 new HttpOverAdbSocket(socket, request_path, callback);
325 void AdbClientSocket::HttpQuery(net::StreamSocket* socket,
326 const std::string& request_path,
327 const SocketCallback& callback) {
328 new HttpOverAdbSocket(socket, request_path, callback);
331 AdbClientSocket::AdbClientSocket(int port)
332 : host_(kLocalhost), port_(port) {
335 AdbClientSocket::~AdbClientSocket() {
338 void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
339 net::IPAddressNumber ip_number;
340 if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
341 callback.Run(net::ERR_FAILED);
345 net::AddressList address_list =
346 net::AddressList::CreateFromIPAddress(ip_number, port_);
347 socket_.reset(new net::TCPClientSocket(address_list, NULL,
348 net::NetLog::Source()));
349 int result = socket_->Connect(callback);
350 if (result != net::ERR_IO_PENDING)
351 callback.Run(result);
354 void AdbClientSocket::SendCommand(const std::string& command,
356 const CommandCallback& callback) {
357 scoped_refptr<net::StringIOBuffer> request_buffer =
358 new net::StringIOBuffer(EncodeMessage(command));
359 int result = socket_->Write(request_buffer.get(),
360 request_buffer->size(),
361 base::Bind(&AdbClientSocket::ReadResponse,
362 base::Unretained(this),
365 if (result != net::ERR_IO_PENDING)
366 ReadResponse(callback, is_void, result);
369 void AdbClientSocket::ReadResponse(const CommandCallback& callback,
373 callback.Run(result, "IO error");
376 scoped_refptr<net::IOBuffer> response_buffer =
377 new net::IOBuffer(kBufferSize);
378 result = socket_->Read(response_buffer.get(),
380 base::Bind(&AdbClientSocket::OnResponseHeader,
381 base::Unretained(this),
385 if (result != net::ERR_IO_PENDING)
386 OnResponseHeader(callback, is_void, response_buffer, result);
389 void AdbClientSocket::OnResponseHeader(
390 const CommandCallback& callback,
392 scoped_refptr<net::IOBuffer> response_buffer,
395 callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
400 std::string data = std::string(response_buffer->data(), result);
402 callback.Run(net::ERR_FAILED, "Response is too short: " + data);
406 std::string status = data.substr(0, 4);
407 if (status != kOkayResponse) {
408 callback.Run(net::ERR_FAILED, data);
412 data = data.substr(4);
415 int payload_length = 0;
417 if (data.length() >= 4 &&
418 base::HexStringToInt(data.substr(0, 4), &payload_length)) {
419 data = data.substr(4);
420 bytes_left = payload_length - result + 8;
424 OnResponseData(callback, data, response_buffer, bytes_left, 0);
426 callback.Run(net::OK, data);
430 void AdbClientSocket::OnResponseData(
431 const CommandCallback& callback,
432 const std::string& response,
433 scoped_refptr<net::IOBuffer> response_buffer,
437 callback.Run(result, "IO error");
441 bytes_left -= result;
442 std::string new_response =
443 response + std::string(response_buffer->data(), result);
444 if (bytes_left == 0) {
445 callback.Run(net::OK, new_response);
450 result = socket_->Read(response_buffer.get(),
452 base::Bind(&AdbClientSocket::OnResponseData,
453 base::Unretained(this),
459 OnResponseData(callback, new_response, response_buffer, bytes_left, result);
460 else if (result != net::ERR_IO_PENDING)
461 callback.Run(net::OK, new_response);