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"
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"
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 typedef base::Callback<void(int, const std::string&)> CommandCallback;
24 typedef base::Callback<void(int, net::StreamSocket*)> SocketCallback;
26 std::string EncodeMessage(const std::string& message) {
27 static const char kHexChars[] = "0123456789ABCDEF";
29 size_t length = message.length();
30 std::string result(4, '\0');
31 char b = reinterpret_cast<const char*>(&length)[1];
32 result[0] = kHexChars[(b >> 4) & 0xf];
33 result[1] = kHexChars[b & 0xf];
34 b = reinterpret_cast<const char*>(&length)[0];
35 result[2] = kHexChars[(b >> 4) & 0xf];
36 result[3] = kHexChars[b & 0xf];
37 return result + message;
40 class AdbTransportSocket : public AdbClientSocket {
42 AdbTransportSocket(int port,
43 const std::string& serial,
44 const std::string& socket_name,
45 const SocketCallback& callback)
46 : AdbClientSocket(port),
48 socket_name_(socket_name),
50 Connect(base::Bind(&AdbTransportSocket::OnConnected,
51 base::Unretained(this)));
55 ~AdbTransportSocket() {}
57 void OnConnected(int result) {
58 if (!CheckNetResultOrDie(result))
60 SendCommand(base::StringPrintf(kHostTransportCommand, serial_.c_str()),
61 true, base::Bind(&AdbTransportSocket::SendLocalAbstract,
62 base::Unretained(this)));
65 void SendLocalAbstract(int result, const std::string& response) {
66 if (!CheckNetResultOrDie(result))
68 SendCommand(socket_name_, true,
69 base::Bind(&AdbTransportSocket::OnSocketAvailable,
70 base::Unretained(this)));
73 void OnSocketAvailable(int result, const std::string& response) {
74 if (!CheckNetResultOrDie(result))
76 callback_.Run(net::OK, socket_.release());
80 bool CheckNetResultOrDie(int result) {
83 callback_.Run(result, NULL);
89 std::string socket_name_;
90 SocketCallback callback_;
93 class AdbQuerySocket : AdbClientSocket {
95 AdbQuerySocket(int port,
96 const std::string& query,
97 const CommandCallback& callback)
98 : AdbClientSocket(port),
100 callback_(callback) {
101 if (Tokenize(query, "|", &queries_) == 0) {
102 CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT);
105 Connect(base::Bind(&AdbQuerySocket::SendNextQuery,
106 base::Unretained(this)));
113 void SendNextQuery(int result) {
114 if (!CheckNetResultOrDie(result))
116 std::string query = queries_[current_query_];
117 if (query.length() > 0xFFFF) {
118 CheckNetResultOrDie(net::ERR_MSG_TOO_BIG);
121 bool is_void = current_query_ < queries_.size() - 1;
122 SendCommand(query, is_void,
123 base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
126 void OnResponse(int result, const std::string& response) {
127 if (++current_query_ < queries_.size()) {
128 SendNextQuery(net::OK);
130 callback_.Run(result, response);
135 bool CheckNetResultOrDie(int result) {
138 callback_.Run(result, std::string());
143 std::vector<std::string> queries_;
144 size_t current_query_;
145 CommandCallback callback_;
151 void AdbClientSocket::AdbQuery(int port,
152 const std::string& query,
153 const CommandCallback& callback) {
154 new AdbQuerySocket(port, query, callback);
158 void AdbClientSocket::TransportQuery(int port,
159 const std::string& serial,
160 const std::string& socket_name,
161 const SocketCallback& callback) {
162 new AdbTransportSocket(port, serial, socket_name, callback);
165 AdbClientSocket::AdbClientSocket(int port)
166 : host_(kLocalhost), port_(port) {
169 AdbClientSocket::~AdbClientSocket() {
172 void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
173 net::IPAddressNumber ip_number;
174 if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
175 callback.Run(net::ERR_FAILED);
179 net::AddressList address_list =
180 net::AddressList::CreateFromIPAddress(ip_number, port_);
181 socket_.reset(new net::TCPClientSocket(address_list, NULL,
182 net::NetLog::Source()));
183 int result = socket_->Connect(callback);
184 if (result != net::ERR_IO_PENDING)
185 callback.Run(result);
188 void AdbClientSocket::SendCommand(const std::string& command,
190 const CommandCallback& callback) {
191 scoped_refptr<net::StringIOBuffer> request_buffer =
192 new net::StringIOBuffer(EncodeMessage(command));
193 int result = socket_->Write(request_buffer.get(),
194 request_buffer->size(),
195 base::Bind(&AdbClientSocket::ReadResponse,
196 base::Unretained(this),
199 if (result != net::ERR_IO_PENDING)
200 ReadResponse(callback, is_void, result);
203 void AdbClientSocket::ReadResponse(const CommandCallback& callback,
207 callback.Run(result, "IO error");
210 scoped_refptr<net::IOBuffer> response_buffer =
211 new net::IOBuffer(kBufferSize);
212 result = socket_->Read(response_buffer.get(),
214 base::Bind(&AdbClientSocket::OnResponseHeader,
215 base::Unretained(this),
219 if (result != net::ERR_IO_PENDING)
220 OnResponseHeader(callback, is_void, response_buffer, result);
223 void AdbClientSocket::OnResponseHeader(
224 const CommandCallback& callback,
226 scoped_refptr<net::IOBuffer> response_buffer,
229 callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
234 std::string data = std::string(response_buffer->data(), result);
236 callback.Run(net::ERR_FAILED, "Response is too short: " + data);
240 std::string status = data.substr(0, 4);
241 if (status != kOkayResponse) {
242 callback.Run(net::ERR_FAILED, data);
246 data = data.substr(4);
249 int payload_length = 0;
251 if (data.length() >= 4 &&
252 base::HexStringToInt(data.substr(0, 4), &payload_length)) {
253 data = data.substr(4);
254 bytes_left = payload_length - result + 8;
258 OnResponseData(callback, data, response_buffer, bytes_left, 0);
260 callback.Run(net::OK, data);
264 void AdbClientSocket::OnResponseData(
265 const CommandCallback& callback,
266 const std::string& response,
267 scoped_refptr<net::IOBuffer> response_buffer,
271 callback.Run(result, "IO error");
275 bytes_left -= result;
276 std::string new_response =
277 response + std::string(response_buffer->data(), result);
278 if (bytes_left == 0) {
279 callback.Run(net::OK, new_response);
284 result = socket_->Read(response_buffer.get(),
286 base::Bind(&AdbClientSocket::OnResponseData,
287 base::Unretained(this),
293 OnResponseData(callback, new_response, response_buffer, bytes_left, result);
294 else if (result != net::ERR_IO_PENDING)
295 callback.Run(net::OK, new_response);