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_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/net_util.h"
15 #include "net/socket/tcp_client_socket.h"
19 const int kBufferSize
= 16 * 1024;
20 const char kOkayResponse
[] = "OKAY";
21 const char kHostTransportCommand
[] = "host:transport:%s";
22 const char kLocalhost
[] = "127.0.0.1";
24 std::string
EncodeMessage(const std::string
& message
) {
25 static const char kHexChars
[] = "0123456789ABCDEF";
27 size_t length
= message
.length();
28 std::string
result(4, '\0');
29 char b
= reinterpret_cast<const char*>(&length
)[1];
30 result
[0] = kHexChars
[(b
>> 4) & 0xf];
31 result
[1] = kHexChars
[b
& 0xf];
32 b
= reinterpret_cast<const char*>(&length
)[0];
33 result
[2] = kHexChars
[(b
>> 4) & 0xf];
34 result
[3] = kHexChars
[b
& 0xf];
35 return result
+ message
;
38 class AdbTransportSocket
: public AdbClientSocket
{
40 AdbTransportSocket(int port
,
41 const std::string
& serial
,
42 const std::string
& socket_name
,
43 const SocketCallback
& callback
)
44 : AdbClientSocket(port
),
46 socket_name_(socket_name
),
48 Connect(base::Bind(&AdbTransportSocket::OnConnected
,
49 base::Unretained(this)));
53 ~AdbTransportSocket() {}
55 void OnConnected(int result
) {
56 if (!CheckNetResultOrDie(result
))
58 SendCommand(base::StringPrintf(kHostTransportCommand
, serial_
.c_str()),
59 true, base::Bind(&AdbTransportSocket::SendLocalAbstract
,
60 base::Unretained(this)));
63 void SendLocalAbstract(int result
, const std::string
& response
) {
64 if (!CheckNetResultOrDie(result
))
66 SendCommand(socket_name_
, true,
67 base::Bind(&AdbTransportSocket::OnSocketAvailable
,
68 base::Unretained(this)));
71 void OnSocketAvailable(int result
, const std::string
& response
) {
72 if (!CheckNetResultOrDie(result
))
74 callback_
.Run(net::OK
, socket_
.Pass());
78 bool CheckNetResultOrDie(int result
) {
81 callback_
.Run(result
, make_scoped_ptr
<net::StreamSocket
>(NULL
));
87 std::string socket_name_
;
88 SocketCallback callback_
;
91 class AdbQuerySocket
: AdbClientSocket
{
93 AdbQuerySocket(int port
,
94 const std::string
& query
,
95 const CommandCallback
& callback
)
96 : AdbClientSocket(port
),
99 queries_
= base::SplitString(query
, "|", base::KEEP_WHITESPACE
,
100 base::SPLIT_WANT_NONEMPTY
);
101 if (queries_
.empty()) {
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
);
247 data
= data
.substr(4);
249 OnResponseData(callback
, data
, response_buffer
, -1, 0);
251 callback
.Run(net::OK
, data
);
254 void AdbClientSocket::OnResponseData(
255 const CommandCallback
& callback
,
256 const std::string
& response
,
257 scoped_refptr
<net::IOBuffer
> response_buffer
,
261 callback
.Run(result
, "IO error");
265 std::string new_response
= response
+
266 std::string(response_buffer
->data(), result
);
268 if (bytes_left
== -1) {
269 // First read the response header.
270 int payload_length
= 0;
271 if (new_response
.length() >= 4 &&
272 base::HexStringToInt(new_response
.substr(0, 4), &payload_length
)) {
273 new_response
= new_response
.substr(4);
274 bytes_left
= payload_length
- new_response
.size();
277 bytes_left
-= result
;
280 if (bytes_left
== 0) {
281 callback
.Run(net::OK
, new_response
);
286 result
= socket_
->Read(response_buffer
.get(),
288 base::Bind(&AdbClientSocket::OnResponseData
,
289 base::Unretained(this),
295 OnResponseData(callback
, new_response
, response_buffer
, bytes_left
, result
);
296 else if (result
!= net::ERR_IO_PENDING
)
297 callback
.Run(net::OK
, new_response
);