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_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "net/base/address_list.h"
14 #include "net/base/completion_callback.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/net_util.h"
17 #include "net/socket/tcp_client_socket.h"
21 const int kBufferSize
= 16 * 1024;
22 const char kOkayResponse
[] = "OKAY";
23 const char kHostTransportCommand
[] = "host:transport:%s";
24 const char kLocalAbstractCommand
[] = "localabstract:%s";
25 const char kLocalhost
[] = "127.0.0.1";
27 typedef base::Callback
<void(int, const std::string
&)> CommandCallback
;
28 typedef base::Callback
<void(int, net::StreamSocket
*)> SocketCallback
;
30 std::string
EncodeMessage(const std::string
& message
) {
31 static const char kHexChars
[] = "0123456789ABCDEF";
33 size_t length
= message
.length();
34 std::string
result(4, '\0');
35 char b
= reinterpret_cast<const char*>(&length
)[1];
36 result
[0] = kHexChars
[(b
>> 4) & 0xf];
37 result
[1] = kHexChars
[b
& 0xf];
38 b
= reinterpret_cast<const char*>(&length
)[0];
39 result
[2] = kHexChars
[(b
>> 4) & 0xf];
40 result
[3] = kHexChars
[b
& 0xf];
41 return result
+ message
;
44 class AdbTransportSocket
: public AdbClientSocket
{
46 AdbTransportSocket(int port
,
47 const std::string
& serial
,
48 const std::string
& socket_name
,
49 const SocketCallback
& callback
)
50 : AdbClientSocket(port
),
52 socket_name_(socket_name
),
54 Connect(base::Bind(&AdbTransportSocket::OnConnected
,
55 base::Unretained(this)));
59 ~AdbTransportSocket() {}
61 void OnConnected(int result
) {
62 if (!CheckNetResultOrDie(result
))
64 SendCommand(base::StringPrintf(kHostTransportCommand
, serial_
.c_str()),
65 true, base::Bind(&AdbTransportSocket::SendLocalAbstract
,
66 base::Unretained(this)));
69 void SendLocalAbstract(int result
, const std::string
& response
) {
70 if (!CheckNetResultOrDie(result
))
72 SendCommand(base::StringPrintf(kLocalAbstractCommand
, socket_name_
.c_str()),
73 true, base::Bind(&AdbTransportSocket::OnSocketAvailable
,
74 base::Unretained(this)));
77 void OnSocketAvailable(int result
, const std::string
& response
) {
78 if (!CheckNetResultOrDie(result
))
80 callback_
.Run(net::OK
, socket_
.release());
84 bool CheckNetResultOrDie(int result
) {
87 callback_
.Run(result
, NULL
);
93 std::string socket_name_
;
94 SocketCallback callback_
;
97 class HttpOverAdbSocket
{
99 HttpOverAdbSocket(int port
,
100 const std::string
& serial
,
101 const std::string
& socket_name
,
102 const std::string
& request
,
103 const CommandCallback
& callback
)
105 command_callback_(callback
),
107 Connect(port
, serial
, socket_name
);
110 HttpOverAdbSocket(int port
,
111 const std::string
& serial
,
112 const std::string
& socket_name
,
113 const std::string
& request
,
114 const SocketCallback
& callback
)
116 socket_callback_(callback
),
118 Connect(port
, serial
, socket_name
);
122 ~HttpOverAdbSocket() {
125 void Connect(int port
,
126 const std::string
& serial
,
127 const std::string
& socket_name
) {
128 AdbClientSocket::TransportQuery(
129 port
, serial
, socket_name
,
130 base::Bind(&HttpOverAdbSocket::OnSocketAvailable
,
131 base::Unretained(this)));
134 void OnSocketAvailable(int result
,
135 net::StreamSocket
* socket
) {
136 if (!CheckNetResultOrDie(result
))
139 socket_
.reset(socket
);
141 scoped_refptr
<net::StringIOBuffer
> request_buffer
=
142 new net::StringIOBuffer(request_
);
144 result
= socket_
->Write(
145 request_buffer
.get(),
146 request_buffer
->size(),
147 base::Bind(&HttpOverAdbSocket::ReadResponse
, base::Unretained(this)));
148 if (result
!= net::ERR_IO_PENDING
)
149 ReadResponse(result
);
152 void ReadResponse(int result
) {
153 if (!CheckNetResultOrDie(result
))
156 scoped_refptr
<net::IOBuffer
> response_buffer
=
157 new net::IOBuffer(kBufferSize
);
159 result
= socket_
->Read(response_buffer
.get(),
161 base::Bind(&HttpOverAdbSocket::OnResponseData
,
162 base::Unretained(this),
165 if (result
!= net::ERR_IO_PENDING
)
166 OnResponseData(response_buffer
, -1, result
);
169 void OnResponseData(scoped_refptr
<net::IOBuffer
> response_buffer
,
172 if (!CheckNetResultOrDie(result
))
175 CheckNetResultOrDie(net::ERR_CONNECTION_CLOSED
);
179 response_
+= std::string(response_buffer
->data(), result
);
180 int expected_length
= 0;
181 if (bytes_total
< 0) {
182 size_t content_pos
= response_
.find("Content-Length:");
183 if (content_pos
!= std::string::npos
) {
184 size_t endline_pos
= response_
.find("\n", content_pos
);
185 if (endline_pos
!= std::string::npos
) {
186 std::string len
= response_
.substr(content_pos
+ 15,
187 endline_pos
- content_pos
- 15);
188 base::TrimWhitespace(len
, base::TRIM_ALL
, &len
);
189 if (!base::StringToInt(len
, &expected_length
)) {
190 CheckNetResultOrDie(net::ERR_FAILED
);
196 body_pos_
= response_
.find("\r\n\r\n");
197 if (body_pos_
!= std::string::npos
) {
199 bytes_total
= body_pos_
+ expected_length
;
203 if (bytes_total
== static_cast<int>(response_
.length())) {
204 if (!command_callback_
.is_null())
205 command_callback_
.Run(body_pos_
, response_
);
207 socket_callback_
.Run(net::OK
, socket_
.release());
212 result
= socket_
->Read(response_buffer
.get(),
214 base::Bind(&HttpOverAdbSocket::OnResponseData
,
215 base::Unretained(this),
218 if (result
!= net::ERR_IO_PENDING
)
219 OnResponseData(response_buffer
, bytes_total
, result
);
222 bool CheckNetResultOrDie(int result
) {
225 if (!command_callback_
.is_null())
226 command_callback_
.Run(result
, std::string());
228 socket_callback_
.Run(result
, NULL
);
233 scoped_ptr
<net::StreamSocket
> socket_
;
234 std::string request_
;
235 std::string response_
;
236 CommandCallback command_callback_
;
237 SocketCallback socket_callback_
;
241 class AdbQuerySocket
: AdbClientSocket
{
243 AdbQuerySocket(int port
,
244 const std::string
& query
,
245 const CommandCallback
& callback
)
246 : AdbClientSocket(port
),
248 callback_(callback
) {
249 queries_
= base::SplitString(
250 query
, "|", base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
251 if (queries_
.empty()) {
252 CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT
);
255 Connect(base::Bind(&AdbQuerySocket::SendNextQuery
, base::Unretained(this)));
262 void SendNextQuery(int result
) {
263 if (!CheckNetResultOrDie(result
))
265 std::string query
= queries_
[current_query_
];
266 if (query
.length() > 0xFFFF) {
267 CheckNetResultOrDie(net::ERR_MSG_TOO_BIG
);
270 bool is_void
= current_query_
< queries_
.size() - 1;
271 SendCommand(query
, is_void
,
272 base::Bind(&AdbQuerySocket::OnResponse
, base::Unretained(this)));
275 void OnResponse(int result
, const std::string
& response
) {
276 if (++current_query_
< queries_
.size()) {
277 SendNextQuery(net::OK
);
279 callback_
.Run(result
, response
);
284 bool CheckNetResultOrDie(int result
) {
287 callback_
.Run(result
, std::string());
292 std::vector
<std::string
> queries_
;
293 size_t current_query_
;
294 CommandCallback callback_
;
300 void AdbClientSocket::AdbQuery(int port
,
301 const std::string
& query
,
302 const CommandCallback
& callback
) {
303 new AdbQuerySocket(port
, query
, callback
);
306 #if defined(DEBUG_DEVTOOLS)
307 static void UseTransportQueryForDesktop(const SocketCallback
& callback
,
308 net::StreamSocket
* socket
,
310 callback
.Run(result
, socket
);
312 #endif // defined(DEBUG_DEVTOOLS)
315 void AdbClientSocket::TransportQuery(int port
,
316 const std::string
& serial
,
317 const std::string
& socket_name
,
318 const SocketCallback
& callback
) {
319 #if defined(DEBUG_DEVTOOLS)
320 if (serial
.empty()) {
321 // Use plain socket for remote debugging on Desktop (debugging purposes).
322 net::IPAddressNumber ip_number
;
323 net::ParseIPLiteralToNumber(kLocalhost
, &ip_number
);
326 if (!base::StringToInt(socket_name
, &tcp_port
))
329 net::AddressList address_list
=
330 net::AddressList::CreateFromIPAddress(ip_number
, tcp_port
);
331 net::TCPClientSocket
* socket
= new net::TCPClientSocket(
332 address_list
, NULL
, net::NetLog::Source());
333 socket
->Connect(base::Bind(&UseTransportQueryForDesktop
, callback
, socket
));
336 #endif // defined(DEBUG_DEVTOOLS)
337 new AdbTransportSocket(port
, serial
, socket_name
, callback
);
341 void AdbClientSocket::HttpQuery(int port
,
342 const std::string
& serial
,
343 const std::string
& socket_name
,
344 const std::string
& request_path
,
345 const CommandCallback
& callback
) {
346 new HttpOverAdbSocket(port
, serial
, socket_name
, request_path
,
351 void AdbClientSocket::HttpQuery(int port
,
352 const std::string
& serial
,
353 const std::string
& socket_name
,
354 const std::string
& request_path
,
355 const SocketCallback
& callback
) {
356 new HttpOverAdbSocket(port
, serial
, socket_name
, request_path
,
360 AdbClientSocket::AdbClientSocket(int port
)
361 : host_(kLocalhost
), port_(port
) {
364 AdbClientSocket::~AdbClientSocket() {
367 void AdbClientSocket::Connect(const net::CompletionCallback
& callback
) {
368 net::IPAddressNumber ip_number
;
369 if (!net::ParseIPLiteralToNumber(host_
, &ip_number
)) {
370 callback
.Run(net::ERR_FAILED
);
374 net::AddressList address_list
=
375 net::AddressList::CreateFromIPAddress(ip_number
, port_
);
376 socket_
.reset(new net::TCPClientSocket(address_list
, NULL
,
377 net::NetLog::Source()));
378 int result
= socket_
->Connect(callback
);
379 if (result
!= net::ERR_IO_PENDING
)
380 callback
.Run(result
);
383 void AdbClientSocket::SendCommand(const std::string
& command
,
385 const CommandCallback
& callback
) {
386 scoped_refptr
<net::StringIOBuffer
> request_buffer
=
387 new net::StringIOBuffer(EncodeMessage(command
));
388 int result
= socket_
->Write(request_buffer
.get(),
389 request_buffer
->size(),
390 base::Bind(&AdbClientSocket::ReadResponse
,
391 base::Unretained(this),
394 if (result
!= net::ERR_IO_PENDING
)
395 ReadResponse(callback
, is_void
, result
);
398 void AdbClientSocket::ReadResponse(const CommandCallback
& callback
,
402 callback
.Run(result
, "IO error");
405 scoped_refptr
<net::IOBuffer
> response_buffer
=
406 new net::IOBuffer(kBufferSize
);
407 result
= socket_
->Read(response_buffer
.get(),
409 base::Bind(&AdbClientSocket::OnResponseHeader
,
410 base::Unretained(this),
414 if (result
!= net::ERR_IO_PENDING
)
415 OnResponseHeader(callback
, is_void
, response_buffer
, result
);
418 void AdbClientSocket::OnResponseHeader(
419 const CommandCallback
& callback
,
421 scoped_refptr
<net::IOBuffer
> response_buffer
,
424 callback
.Run(result
== 0 ? net::ERR_CONNECTION_CLOSED
: result
,
429 std::string data
= std::string(response_buffer
->data(), result
);
431 callback
.Run(net::ERR_FAILED
, "Response is too short: " + data
);
435 std::string status
= data
.substr(0, 4);
436 if (status
!= kOkayResponse
) {
437 callback
.Run(net::ERR_FAILED
, data
);
441 data
= data
.substr(4);
444 int payload_length
= 0;
446 if (data
.length() >= 4 &&
447 base::HexStringToInt(data
.substr(0, 4), &payload_length
)) {
448 data
= data
.substr(4);
449 bytes_left
= payload_length
- result
+ 8;
453 OnResponseData(callback
, data
, response_buffer
, bytes_left
, 0);
455 callback
.Run(net::OK
, data
);
459 void AdbClientSocket::OnResponseData(
460 const CommandCallback
& callback
,
461 const std::string
& response
,
462 scoped_refptr
<net::IOBuffer
> response_buffer
,
466 callback
.Run(result
, "IO error");
470 bytes_left
-= result
;
471 std::string new_response
=
472 response
+ std::string(response_buffer
->data(), result
);
473 if (bytes_left
== 0) {
474 callback
.Run(net::OK
, new_response
);
479 result
= socket_
->Read(response_buffer
.get(),
481 base::Bind(&AdbClientSocket::OnResponseData
,
482 base::Unretained(this),
488 OnResponseData(callback
, new_response
, response_buffer
, bytes_left
, result
);
489 else if (result
!= net::ERR_IO_PENDING
)
490 callback
.Run(net::OK
, new_response
);