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/test/chromedriver/net/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 kLocalAbstractCommand
[] = "localabstract:%s";
24 const char kLocalhost
[] = "127.0.0.1";
26 typedef base::Callback
<void(int, const std::string
&)> CommandCallback
;
27 typedef base::Callback
<void(int, net::StreamSocket
*)> SocketCallback
;
29 std::string
EncodeMessage(const std::string
& message
) {
30 static const char kHexChars
[] = "0123456789ABCDEF";
32 size_t length
= message
.length();
33 std::string
result(4, '\0');
34 char b
= reinterpret_cast<const char*>(&length
)[1];
35 result
[0] = kHexChars
[(b
>> 4) & 0xf];
36 result
[1] = kHexChars
[b
& 0xf];
37 b
= reinterpret_cast<const char*>(&length
)[0];
38 result
[2] = kHexChars
[(b
>> 4) & 0xf];
39 result
[3] = kHexChars
[b
& 0xf];
40 return result
+ message
;
43 class AdbTransportSocket
: public AdbClientSocket
{
45 AdbTransportSocket(int port
,
46 const std::string
& serial
,
47 const std::string
& socket_name
,
48 const SocketCallback
& callback
)
49 : AdbClientSocket(port
),
51 socket_name_(socket_name
),
53 Connect(base::Bind(&AdbTransportSocket::OnConnected
,
54 base::Unretained(this)));
58 ~AdbTransportSocket() {}
60 void OnConnected(int result
) {
61 if (!CheckNetResultOrDie(result
))
63 SendCommand(base::StringPrintf(kHostTransportCommand
, serial_
.c_str()),
64 true, base::Bind(&AdbTransportSocket::SendLocalAbstract
,
65 base::Unretained(this)));
68 void SendLocalAbstract(int result
, const std::string
& response
) {
69 if (!CheckNetResultOrDie(result
))
71 SendCommand(base::StringPrintf(kLocalAbstractCommand
, socket_name_
.c_str()),
72 true, base::Bind(&AdbTransportSocket::OnSocketAvailable
,
73 base::Unretained(this)));
76 void OnSocketAvailable(int result
, const std::string
& response
) {
77 if (!CheckNetResultOrDie(result
))
79 callback_
.Run(net::OK
, socket_
.release());
83 bool CheckNetResultOrDie(int result
) {
86 callback_
.Run(result
, NULL
);
92 std::string socket_name_
;
93 SocketCallback callback_
;
96 class HttpOverAdbSocket
{
98 HttpOverAdbSocket(int port
,
99 const std::string
& serial
,
100 const std::string
& socket_name
,
101 const std::string
& request
,
102 const CommandCallback
& callback
)
104 command_callback_(callback
),
106 Connect(port
, serial
, socket_name
);
109 HttpOverAdbSocket(int port
,
110 const std::string
& serial
,
111 const std::string
& socket_name
,
112 const std::string
& request
,
113 const SocketCallback
& callback
)
115 socket_callback_(callback
),
117 Connect(port
, serial
, socket_name
);
121 ~HttpOverAdbSocket() {
124 void Connect(int port
,
125 const std::string
& serial
,
126 const std::string
& socket_name
) {
127 AdbClientSocket::TransportQuery(
128 port
, serial
, socket_name
,
129 base::Bind(&HttpOverAdbSocket::OnSocketAvailable
,
130 base::Unretained(this)));
133 void OnSocketAvailable(int result
,
134 net::StreamSocket
* socket
) {
135 if (!CheckNetResultOrDie(result
))
138 socket_
.reset(socket
);
140 scoped_refptr
<net::StringIOBuffer
> request_buffer
=
141 new net::StringIOBuffer(request_
);
143 result
= socket_
->Write(
144 request_buffer
.get(),
145 request_buffer
->size(),
146 base::Bind(&HttpOverAdbSocket::ReadResponse
, base::Unretained(this)));
147 if (result
!= net::ERR_IO_PENDING
)
148 ReadResponse(result
);
151 void ReadResponse(int result
) {
152 if (!CheckNetResultOrDie(result
))
155 scoped_refptr
<net::IOBuffer
> response_buffer
=
156 new net::IOBuffer(kBufferSize
);
158 result
= socket_
->Read(response_buffer
.get(),
160 base::Bind(&HttpOverAdbSocket::OnResponseData
,
161 base::Unretained(this),
164 if (result
!= net::ERR_IO_PENDING
)
165 OnResponseData(response_buffer
, -1, result
);
168 void OnResponseData(scoped_refptr
<net::IOBuffer
> response_buffer
,
171 if (!CheckNetResultOrDie(result
))
174 CheckNetResultOrDie(net::ERR_CONNECTION_CLOSED
);
178 response_
+= std::string(response_buffer
->data(), result
);
179 int expected_length
= 0;
180 if (bytes_total
< 0) {
181 size_t content_pos
= response_
.find("Content-Length:");
182 if (content_pos
!= std::string::npos
) {
183 size_t endline_pos
= response_
.find("\n", content_pos
);
184 if (endline_pos
!= std::string::npos
) {
185 std::string len
= response_
.substr(content_pos
+ 15,
186 endline_pos
- content_pos
- 15);
187 base::TrimWhitespace(len
, base::TRIM_ALL
, &len
);
188 if (!base::StringToInt(len
, &expected_length
)) {
189 CheckNetResultOrDie(net::ERR_FAILED
);
195 body_pos_
= response_
.find("\r\n\r\n");
196 if (body_pos_
!= std::string::npos
) {
198 bytes_total
= body_pos_
+ expected_length
;
202 if (bytes_total
== static_cast<int>(response_
.length())) {
203 if (!command_callback_
.is_null())
204 command_callback_
.Run(body_pos_
, response_
);
206 socket_callback_
.Run(net::OK
, socket_
.release());
211 result
= socket_
->Read(response_buffer
.get(),
213 base::Bind(&HttpOverAdbSocket::OnResponseData
,
214 base::Unretained(this),
217 if (result
!= net::ERR_IO_PENDING
)
218 OnResponseData(response_buffer
, bytes_total
, result
);
221 bool CheckNetResultOrDie(int result
) {
224 if (!command_callback_
.is_null())
225 command_callback_
.Run(result
, std::string());
227 socket_callback_
.Run(result
, NULL
);
232 scoped_ptr
<net::StreamSocket
> socket_
;
233 std::string request_
;
234 std::string response_
;
235 CommandCallback command_callback_
;
236 SocketCallback socket_callback_
;
240 class AdbQuerySocket
: AdbClientSocket
{
242 AdbQuerySocket(int port
,
243 const std::string
& query
,
244 const CommandCallback
& callback
)
245 : AdbClientSocket(port
),
247 callback_(callback
) {
248 if (Tokenize(query
, "|", &queries_
) == 0) {
249 CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT
);
252 Connect(base::Bind(&AdbQuerySocket::SendNextQuery
,
253 base::Unretained(this)));
260 void SendNextQuery(int result
) {
261 if (!CheckNetResultOrDie(result
))
263 std::string query
= queries_
[current_query_
];
264 if (query
.length() > 0xFFFF) {
265 CheckNetResultOrDie(net::ERR_MSG_TOO_BIG
);
268 bool is_void
= current_query_
< queries_
.size() - 1;
269 SendCommand(query
, is_void
,
270 base::Bind(&AdbQuerySocket::OnResponse
, base::Unretained(this)));
273 void OnResponse(int result
, const std::string
& response
) {
274 if (++current_query_
< queries_
.size()) {
275 SendNextQuery(net::OK
);
277 callback_
.Run(result
, response
);
282 bool CheckNetResultOrDie(int result
) {
285 callback_
.Run(result
, std::string());
290 std::vector
<std::string
> queries_
;
291 size_t current_query_
;
292 CommandCallback callback_
;
298 void AdbClientSocket::AdbQuery(int port
,
299 const std::string
& query
,
300 const CommandCallback
& callback
) {
301 new AdbQuerySocket(port
, query
, callback
);
304 #if defined(DEBUG_DEVTOOLS)
305 static void UseTransportQueryForDesktop(const SocketCallback
& callback
,
306 net::StreamSocket
* socket
,
308 callback
.Run(result
, socket
);
310 #endif // defined(DEBUG_DEVTOOLS)
313 void AdbClientSocket::TransportQuery(int port
,
314 const std::string
& serial
,
315 const std::string
& socket_name
,
316 const SocketCallback
& callback
) {
317 #if defined(DEBUG_DEVTOOLS)
318 if (serial
.empty()) {
319 // Use plain socket for remote debugging on Desktop (debugging purposes).
320 net::IPAddressNumber ip_number
;
321 net::ParseIPLiteralToNumber(kLocalhost
, &ip_number
);
324 if (!base::StringToInt(socket_name
, &tcp_port
))
327 net::AddressList address_list
=
328 net::AddressList::CreateFromIPAddress(ip_number
, tcp_port
);
329 net::TCPClientSocket
* socket
= new net::TCPClientSocket(
330 address_list
, NULL
, net::NetLog::Source());
331 socket
->Connect(base::Bind(&UseTransportQueryForDesktop
, callback
, socket
));
334 #endif // defined(DEBUG_DEVTOOLS)
335 new AdbTransportSocket(port
, serial
, socket_name
, callback
);
339 void AdbClientSocket::HttpQuery(int port
,
340 const std::string
& serial
,
341 const std::string
& socket_name
,
342 const std::string
& request_path
,
343 const CommandCallback
& callback
) {
344 new HttpOverAdbSocket(port
, serial
, socket_name
, request_path
,
349 void AdbClientSocket::HttpQuery(int port
,
350 const std::string
& serial
,
351 const std::string
& socket_name
,
352 const std::string
& request_path
,
353 const SocketCallback
& callback
) {
354 new HttpOverAdbSocket(port
, serial
, socket_name
, request_path
,
358 AdbClientSocket::AdbClientSocket(int port
)
359 : host_(kLocalhost
), port_(port
) {
362 AdbClientSocket::~AdbClientSocket() {
365 void AdbClientSocket::Connect(const net::CompletionCallback
& callback
) {
366 net::IPAddressNumber ip_number
;
367 if (!net::ParseIPLiteralToNumber(host_
, &ip_number
)) {
368 callback
.Run(net::ERR_FAILED
);
372 net::AddressList address_list
=
373 net::AddressList::CreateFromIPAddress(ip_number
, port_
);
374 socket_
.reset(new net::TCPClientSocket(address_list
, NULL
,
375 net::NetLog::Source()));
376 int result
= socket_
->Connect(callback
);
377 if (result
!= net::ERR_IO_PENDING
)
378 callback
.Run(result
);
381 void AdbClientSocket::SendCommand(const std::string
& command
,
383 const CommandCallback
& callback
) {
384 scoped_refptr
<net::StringIOBuffer
> request_buffer
=
385 new net::StringIOBuffer(EncodeMessage(command
));
386 int result
= socket_
->Write(request_buffer
.get(),
387 request_buffer
->size(),
388 base::Bind(&AdbClientSocket::ReadResponse
,
389 base::Unretained(this),
392 if (result
!= net::ERR_IO_PENDING
)
393 ReadResponse(callback
, is_void
, result
);
396 void AdbClientSocket::ReadResponse(const CommandCallback
& callback
,
400 callback
.Run(result
, "IO error");
403 scoped_refptr
<net::IOBuffer
> response_buffer
=
404 new net::IOBuffer(kBufferSize
);
405 result
= socket_
->Read(response_buffer
.get(),
407 base::Bind(&AdbClientSocket::OnResponseHeader
,
408 base::Unretained(this),
412 if (result
!= net::ERR_IO_PENDING
)
413 OnResponseHeader(callback
, is_void
, response_buffer
, result
);
416 void AdbClientSocket::OnResponseHeader(
417 const CommandCallback
& callback
,
419 scoped_refptr
<net::IOBuffer
> response_buffer
,
422 callback
.Run(result
== 0 ? net::ERR_CONNECTION_CLOSED
: result
,
427 std::string data
= std::string(response_buffer
->data(), result
);
429 callback
.Run(net::ERR_FAILED
, "Response is too short: " + data
);
433 std::string status
= data
.substr(0, 4);
434 if (status
!= kOkayResponse
) {
435 callback
.Run(net::ERR_FAILED
, data
);
439 data
= data
.substr(4);
442 int payload_length
= 0;
444 if (data
.length() >= 4 &&
445 base::HexStringToInt(data
.substr(0, 4), &payload_length
)) {
446 data
= data
.substr(4);
447 bytes_left
= payload_length
- result
+ 8;
451 OnResponseData(callback
, data
, response_buffer
, bytes_left
, 0);
453 callback
.Run(net::OK
, data
);
457 void AdbClientSocket::OnResponseData(
458 const CommandCallback
& callback
,
459 const std::string
& response
,
460 scoped_refptr
<net::IOBuffer
> response_buffer
,
464 callback
.Run(result
, "IO error");
468 bytes_left
-= result
;
469 std::string new_response
=
470 response
+ std::string(response_buffer
->data(), result
);
471 if (bytes_left
== 0) {
472 callback
.Run(net::OK
, new_response
);
477 result
= socket_
->Read(response_buffer
.get(),
479 base::Bind(&AdbClientSocket::OnResponseData
,
480 base::Unretained(this),
486 OnResponseData(callback
, new_response
, response_buffer
, bytes_left
, result
);
487 else if (result
!= net::ERR_IO_PENDING
)
488 callback
.Run(net::OK
, new_response
);