blob: 98e906514bd3e9b0da3f36e85cfb93263568a6b1 [file] [log] [blame]
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001// 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.
4
5#include "chrome/browser/devtools/adb_client_socket.h"
6
7#include "base/bind.h"
8#include "base/compiler_specific.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00009#include "base/strings/string_number_conversions.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010010#include "base/strings/string_util.h"
11#include "base/strings/stringprintf.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010012#include "net/base/address_list.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000013#include "net/base/completion_callback.h"
14#include "net/base/net_errors.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010015#include "net/base/net_util.h"
16#include "net/socket/tcp_client_socket.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000017
18namespace {
19
20const int kBufferSize = 16 * 1024;
21const int kResponseBufferSize = 16;
22const char kOkayResponse[] = "OKAY";
23const char kHostTransportCommand[] = "host:transport:%s";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000024const char kLocalhost[] = "127.0.0.1";
25
26typedef base::Callback<void(int, const std::string&)> CommandCallback;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010027typedef base::Callback<void(int, net::StreamSocket*)> SocketCallback;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000028
29std::string EncodeMessage(const std::string& message) {
30 static const char kHexChars[] = "0123456789ABCDEF";
31
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;
41}
42
43class AdbTransportSocket : public AdbClientSocket {
44 public:
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010045 AdbTransportSocket(int port,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000046 const std::string& serial,
47 const std::string& socket_name,
48 const SocketCallback& callback)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010049 : AdbClientSocket(port),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000050 serial_(serial),
51 socket_name_(socket_name),
52 callback_(callback) {
53 Connect(base::Bind(&AdbTransportSocket::OnConnected,
54 base::Unretained(this)));
55 }
56
57 private:
58 ~AdbTransportSocket() {}
59
60 void OnConnected(int result) {
61 if (!CheckNetResultOrDie(result))
62 return;
63 SendCommand(base::StringPrintf(kHostTransportCommand, serial_.c_str()),
64 true, base::Bind(&AdbTransportSocket::SendLocalAbstract,
65 base::Unretained(this)));
66 }
67
68 void SendLocalAbstract(int result, const std::string& response) {
69 if (!CheckNetResultOrDie(result))
70 return;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010071 SendCommand(socket_name_, true,
72 base::Bind(&AdbTransportSocket::OnSocketAvailable,
73 base::Unretained(this)));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000074 }
75
76 void OnSocketAvailable(int result, const std::string& response) {
77 if (!CheckNetResultOrDie(result))
78 return;
79 callback_.Run(net::OK, socket_.release());
80 delete this;
81 }
82
83 bool CheckNetResultOrDie(int result) {
84 if (result >= 0)
85 return true;
86 callback_.Run(result, NULL);
87 delete this;
88 return false;
89 }
90
91 std::string serial_;
92 std::string socket_name_;
93 SocketCallback callback_;
94};
95
96class HttpOverAdbSocket {
97 public:
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010098 HttpOverAdbSocket(net::StreamSocket* socket,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000099 const std::string& request,
100 const CommandCallback& callback)
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100101 : socket_(socket),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000102 command_callback_(callback),
103 body_pos_(0) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100104 SendRequest(request);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000105 }
106
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100107 HttpOverAdbSocket(net::StreamSocket* socket,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000108 const std::string& request,
109 const SocketCallback& callback)
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100110 : socket_(socket),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000111 socket_callback_(callback),
112 body_pos_(0) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100113 SendRequest(request);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000114 }
115
116 private:
117 ~HttpOverAdbSocket() {
118 }
119
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100120 void SendRequest(const std::string& request) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000121 scoped_refptr<net::StringIOBuffer> request_buffer =
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100122 new net::StringIOBuffer(request);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000123
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100124 int result = socket_->Write(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100125 request_buffer.get(),
126 request_buffer->size(),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000127 base::Bind(&HttpOverAdbSocket::ReadResponse, base::Unretained(this)));
128 if (result != net::ERR_IO_PENDING)
129 ReadResponse(result);
130 }
131
132 void ReadResponse(int result) {
133 if (!CheckNetResultOrDie(result))
134 return;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000135 scoped_refptr<net::IOBuffer> response_buffer =
136 new net::IOBuffer(kBufferSize);
137
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100138 result = socket_->Read(response_buffer.get(),
139 kBufferSize,
140 base::Bind(&HttpOverAdbSocket::OnResponseData,
141 base::Unretained(this),
142 response_buffer,
143 -1));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000144 if (result != net::ERR_IO_PENDING)
145 OnResponseData(response_buffer, -1, result);
146 }
147
148 void OnResponseData(scoped_refptr<net::IOBuffer> response_buffer,
149 int bytes_total,
150 int result) {
151 if (!CheckNetResultOrDie(result))
152 return;
153 if (result == 0) {
154 CheckNetResultOrDie(net::ERR_CONNECTION_CLOSED);
155 return;
156 }
157
158 response_ += std::string(response_buffer->data(), result);
159 int expected_length = 0;
160 if (bytes_total < 0) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100161 // TODO(kaznacheev): Use net::HttpResponseHeader to parse the header.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000162 size_t content_pos = response_.find("Content-Length:");
163 if (content_pos != std::string::npos) {
164 size_t endline_pos = response_.find("\n", content_pos);
165 if (endline_pos != std::string::npos) {
166 std::string len = response_.substr(content_pos + 15,
167 endline_pos - content_pos - 15);
168 TrimWhitespace(len, TRIM_ALL, &len);
169 if (!base::StringToInt(len, &expected_length)) {
170 CheckNetResultOrDie(net::ERR_FAILED);
171 return;
172 }
173 }
174 }
175
176 body_pos_ = response_.find("\r\n\r\n");
177 if (body_pos_ != std::string::npos) {
178 body_pos_ += 4;
179 bytes_total = body_pos_ + expected_length;
180 }
181 }
182
183 if (bytes_total == static_cast<int>(response_.length())) {
184 if (!command_callback_.is_null())
Ben Murdochbb1529c2013-08-08 10:24:53 +0100185 command_callback_.Run(net::OK, response_.substr(body_pos_));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000186 else
187 socket_callback_.Run(net::OK, socket_.release());
188 delete this;
189 return;
190 }
191
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100192 result = socket_->Read(response_buffer.get(),
193 kBufferSize,
194 base::Bind(&HttpOverAdbSocket::OnResponseData,
195 base::Unretained(this),
196 response_buffer,
197 bytes_total));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000198 if (result != net::ERR_IO_PENDING)
199 OnResponseData(response_buffer, bytes_total, result);
200 }
201
202 bool CheckNetResultOrDie(int result) {
203 if (result >= 0)
204 return true;
205 if (!command_callback_.is_null())
206 command_callback_.Run(result, std::string());
207 else
208 socket_callback_.Run(result, NULL);
209 delete this;
210 return false;
211 }
212
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100213 scoped_ptr<net::StreamSocket> socket_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000214 std::string response_;
215 CommandCallback command_callback_;
216 SocketCallback socket_callback_;
217 size_t body_pos_;
218};
219
220class AdbQuerySocket : AdbClientSocket {
221 public:
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100222 AdbQuerySocket(int port,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000223 const std::string& query,
224 const CommandCallback& callback)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100225 : AdbClientSocket(port),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000226 current_query_(0),
227 callback_(callback) {
228 if (Tokenize(query, "|", &queries_) == 0) {
229 CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT);
230 return;
231 }
232 Connect(base::Bind(&AdbQuerySocket::SendNextQuery,
233 base::Unretained(this)));
234 }
235
236 private:
237 ~AdbQuerySocket() {
238 }
239
240 void SendNextQuery(int result) {
241 if (!CheckNetResultOrDie(result))
242 return;
243 std::string query = queries_[current_query_];
244 if (query.length() > 0xFFFF) {
245 CheckNetResultOrDie(net::ERR_MSG_TOO_BIG);
246 return;
247 }
248 bool is_void = current_query_ < queries_.size() - 1;
249 SendCommand(query, is_void,
250 base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
251 }
252
253 void OnResponse(int result, const std::string& response) {
254 if (++current_query_ < queries_.size()) {
255 SendNextQuery(net::OK);
256 } else {
257 callback_.Run(result, response);
258 delete this;
259 }
260 }
261
262 bool CheckNetResultOrDie(int result) {
263 if (result >= 0)
264 return true;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100265 callback_.Run(result, std::string());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000266 delete this;
267 return false;
268 }
269
270 std::vector<std::string> queries_;
271 size_t current_query_;
272 CommandCallback callback_;
273};
274
275} // namespace
276
277// static
278void AdbClientSocket::AdbQuery(int port,
279 const std::string& query,
280 const CommandCallback& callback) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100281 new AdbQuerySocket(port, query, callback);
282}
283
284#if defined(DEBUG_DEVTOOLS)
285static void UseTransportQueryForDesktop(const SocketCallback& callback,
286 net::StreamSocket* socket,
287 int result) {
288 callback.Run(result, socket);
289}
290#endif // defined(DEBUG_DEVTOOLS)
291
292// static
293void AdbClientSocket::TransportQuery(int port,
294 const std::string& serial,
295 const std::string& socket_name,
296 const SocketCallback& callback) {
297#if defined(DEBUG_DEVTOOLS)
298 if (serial.empty()) {
299 // Use plain socket for remote debugging on Desktop (debugging purposes).
300 net::IPAddressNumber ip_number;
301 net::ParseIPLiteralToNumber(kLocalhost, &ip_number);
302
303 int tcp_port = 0;
304 if (!base::StringToInt(socket_name, &tcp_port))
305 tcp_port = 9222;
306
307 net::AddressList address_list =
308 net::AddressList::CreateFromIPAddress(ip_number, tcp_port);
309 net::TCPClientSocket* socket = new net::TCPClientSocket(
310 address_list, NULL, net::NetLog::Source());
311 socket->Connect(base::Bind(&UseTransportQueryForDesktop, callback, socket));
312 return;
313 }
314#endif // defined(DEBUG_DEVTOOLS)
315 new AdbTransportSocket(port, serial, socket_name, callback);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000316}
317
318// static
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100319void AdbClientSocket::HttpQuery(net::StreamSocket* socket,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000320 const std::string& request_path,
321 const CommandCallback& callback) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100322 new HttpOverAdbSocket(socket, request_path, callback);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000323}
324
325// static
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100326void AdbClientSocket::HttpQuery(net::StreamSocket* socket,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000327 const std::string& request_path,
328 const SocketCallback& callback) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100329 new HttpOverAdbSocket(socket, request_path, callback);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000330}
331
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100332AdbClientSocket::AdbClientSocket(int port)
333 : host_(kLocalhost), port_(port) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000334}
335
336AdbClientSocket::~AdbClientSocket() {
337}
338
339void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
340 net::IPAddressNumber ip_number;
341 if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
342 callback.Run(net::ERR_FAILED);
343 return;
344 }
345
346 net::AddressList address_list =
347 net::AddressList::CreateFromIPAddress(ip_number, port_);
348 socket_.reset(new net::TCPClientSocket(address_list, NULL,
349 net::NetLog::Source()));
350 int result = socket_->Connect(callback);
351 if (result != net::ERR_IO_PENDING)
352 callback.Run(result);
353}
354
355void AdbClientSocket::SendCommand(const std::string& command,
356 bool is_void,
357 const CommandCallback& callback) {
358 scoped_refptr<net::StringIOBuffer> request_buffer =
359 new net::StringIOBuffer(EncodeMessage(command));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100360 int result = socket_->Write(request_buffer.get(),
361 request_buffer->size(),
362 base::Bind(&AdbClientSocket::ReadResponse,
363 base::Unretained(this),
364 callback,
365 is_void));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000366 if (result != net::ERR_IO_PENDING)
367 ReadResponse(callback, is_void, result);
368}
369
370void AdbClientSocket::ReadResponse(const CommandCallback& callback,
371 bool is_void,
372 int result) {
373 if (result < 0) {
374 callback.Run(result, "IO error");
375 return;
376 }
377 scoped_refptr<net::IOBuffer> response_buffer =
378 new net::IOBuffer(kBufferSize);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100379 result = socket_->Read(response_buffer.get(),
380 kBufferSize,
381 base::Bind(&AdbClientSocket::OnResponseHeader,
382 base::Unretained(this),
383 callback,
384 is_void,
385 response_buffer));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000386 if (result != net::ERR_IO_PENDING)
387 OnResponseHeader(callback, is_void, response_buffer, result);
388}
389
390void AdbClientSocket::OnResponseHeader(
391 const CommandCallback& callback,
392 bool is_void,
393 scoped_refptr<net::IOBuffer> response_buffer,
394 int result) {
395 if (result <= 0) {
396 callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
397 "IO error");
398 return;
399 }
400
401 std::string data = std::string(response_buffer->data(), result);
402 if (result < 4) {
403 callback.Run(net::ERR_FAILED, "Response is too short: " + data);
404 return;
405 }
406
407 std::string status = data.substr(0, 4);
408 if (status != kOkayResponse) {
409 callback.Run(net::ERR_FAILED, data);
410 return;
411 }
412
413 data = data.substr(4);
414
415 if (!is_void) {
416 int payload_length = 0;
417 int bytes_left = -1;
418 if (data.length() >= 4 &&
419 base::HexStringToInt(data.substr(0, 4), &payload_length)) {
420 data = data.substr(4);
421 bytes_left = payload_length - result + 8;
422 } else {
423 bytes_left = -1;
424 }
425 OnResponseData(callback, data, response_buffer, bytes_left, 0);
426 } else {
427 callback.Run(net::OK, data);
428 }
429}
430
431void AdbClientSocket::OnResponseData(
432 const CommandCallback& callback,
433 const std::string& response,
434 scoped_refptr<net::IOBuffer> response_buffer,
435 int bytes_left,
436 int result) {
437 if (result < 0) {
438 callback.Run(result, "IO error");
439 return;
440 }
441
442 bytes_left -= result;
443 std::string new_response =
444 response + std::string(response_buffer->data(), result);
445 if (bytes_left == 0) {
446 callback.Run(net::OK, new_response);
447 return;
448 }
449
450 // Read tail
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100451 result = socket_->Read(response_buffer.get(),
452 kBufferSize,
453 base::Bind(&AdbClientSocket::OnResponseData,
454 base::Unretained(this),
455 callback,
456 new_response,
457 response_buffer,
458 bytes_left));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000459 if (result > 0)
460 OnResponseData(callback, new_response, response_buffer, bytes_left, result);
461 else if (result != net::ERR_IO_PENDING)
462 callback.Run(net::OK, new_response);
463}