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
);
284 void AdbClientSocket::TransportQuery(int port
,
285 const std::string
& serial
,
286 const std::string
& socket_name
,
287 const SocketCallback
& callback
) {
288 new AdbTransportSocket(port
, serial
, socket_name
, callback
);
292 void AdbClientSocket::HttpQuery(net::StreamSocket
* socket
,
293 const std::string
& request_path
,
294 const CommandCallback
& callback
) {
295 new HttpOverAdbSocket(socket
, request_path
, callback
);
299 void AdbClientSocket::HttpQuery(net::StreamSocket
* socket
,
300 const std::string
& request_path
,
301 const SocketCallback
& callback
) {
302 new HttpOverAdbSocket(socket
, request_path
, callback
);
305 AdbClientSocket::AdbClientSocket(int port
)
306 : host_(kLocalhost
), port_(port
) {
309 AdbClientSocket::~AdbClientSocket() {
312 void AdbClientSocket::Connect(const net::CompletionCallback
& callback
) {
313 net::IPAddressNumber ip_number
;
314 if (!net::ParseIPLiteralToNumber(host_
, &ip_number
)) {
315 callback
.Run(net::ERR_FAILED
);
319 net::AddressList address_list
=
320 net::AddressList::CreateFromIPAddress(ip_number
, port_
);
321 socket_
.reset(new net::TCPClientSocket(address_list
, NULL
,
322 net::NetLog::Source()));
323 int result
= socket_
->Connect(callback
);
324 if (result
!= net::ERR_IO_PENDING
)
325 callback
.Run(result
);
328 void AdbClientSocket::SendCommand(const std::string
& command
,
330 const CommandCallback
& callback
) {
331 scoped_refptr
<net::StringIOBuffer
> request_buffer
=
332 new net::StringIOBuffer(EncodeMessage(command
));
333 int result
= socket_
->Write(request_buffer
.get(),
334 request_buffer
->size(),
335 base::Bind(&AdbClientSocket::ReadResponse
,
336 base::Unretained(this),
339 if (result
!= net::ERR_IO_PENDING
)
340 ReadResponse(callback
, is_void
, result
);
343 void AdbClientSocket::ReadResponse(const CommandCallback
& callback
,
347 callback
.Run(result
, "IO error");
350 scoped_refptr
<net::IOBuffer
> response_buffer
=
351 new net::IOBuffer(kBufferSize
);
352 result
= socket_
->Read(response_buffer
.get(),
354 base::Bind(&AdbClientSocket::OnResponseHeader
,
355 base::Unretained(this),
359 if (result
!= net::ERR_IO_PENDING
)
360 OnResponseHeader(callback
, is_void
, response_buffer
, result
);
363 void AdbClientSocket::OnResponseHeader(
364 const CommandCallback
& callback
,
366 scoped_refptr
<net::IOBuffer
> response_buffer
,
369 callback
.Run(result
== 0 ? net::ERR_CONNECTION_CLOSED
: result
,
374 std::string data
= std::string(response_buffer
->data(), result
);
376 callback
.Run(net::ERR_FAILED
, "Response is too short: " + data
);
380 std::string status
= data
.substr(0, 4);
381 if (status
!= kOkayResponse
) {
382 callback
.Run(net::ERR_FAILED
, data
);
386 data
= data
.substr(4);
389 int payload_length
= 0;
391 if (data
.length() >= 4 &&
392 base::HexStringToInt(data
.substr(0, 4), &payload_length
)) {
393 data
= data
.substr(4);
394 bytes_left
= payload_length
- result
+ 8;
398 OnResponseData(callback
, data
, response_buffer
, bytes_left
, 0);
400 callback
.Run(net::OK
, data
);
404 void AdbClientSocket::OnResponseData(
405 const CommandCallback
& callback
,
406 const std::string
& response
,
407 scoped_refptr
<net::IOBuffer
> response_buffer
,
411 callback
.Run(result
, "IO error");
415 bytes_left
-= result
;
416 std::string new_response
=
417 response
+ std::string(response_buffer
->data(), result
);
418 if (bytes_left
== 0) {
419 callback
.Run(net::OK
, new_response
);
424 result
= socket_
->Read(response_buffer
.get(),
426 base::Bind(&AdbClientSocket::OnResponseData
,
427 base::Unretained(this),
433 OnResponseData(callback
, new_response
, response_buffer
, bytes_left
, result
);
434 else if (result
!= net::ERR_IO_PENDING
)
435 callback
.Run(net::OK
, new_response
);