- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / adb_client_socket.cc
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.
4
5 #include "chrome/browser/devtools/adb_client_socket.h"
6
7 #include "base/bind.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"
17
18 namespace {
19
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";
24
25 typedef base::Callback<void(int, const std::string&)> CommandCallback;
26 typedef base::Callback<void(int, net::StreamSocket*)> SocketCallback;
27
28 std::string EncodeMessage(const std::string& message) {
29   static const char kHexChars[] = "0123456789ABCDEF";
30
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;
40 }
41
42 class AdbTransportSocket : public AdbClientSocket {
43  public:
44   AdbTransportSocket(int port,
45                      const std::string& serial,
46                      const std::string& socket_name,
47                      const SocketCallback& callback)
48     : AdbClientSocket(port),
49       serial_(serial),
50       socket_name_(socket_name),
51       callback_(callback) {
52     Connect(base::Bind(&AdbTransportSocket::OnConnected,
53                        base::Unretained(this)));
54   }
55
56  private:
57   ~AdbTransportSocket() {}
58
59   void OnConnected(int result) {
60     if (!CheckNetResultOrDie(result))
61       return;
62     SendCommand(base::StringPrintf(kHostTransportCommand, serial_.c_str()),
63         true, base::Bind(&AdbTransportSocket::SendLocalAbstract,
64                          base::Unretained(this)));
65   }
66
67   void SendLocalAbstract(int result, const std::string& response) {
68     if (!CheckNetResultOrDie(result))
69       return;
70     SendCommand(socket_name_, true,
71                 base::Bind(&AdbTransportSocket::OnSocketAvailable,
72                            base::Unretained(this)));
73   }
74
75   void OnSocketAvailable(int result, const std::string& response) {
76     if (!CheckNetResultOrDie(result))
77       return;
78     callback_.Run(net::OK, socket_.release());
79     delete this;
80   }
81
82   bool CheckNetResultOrDie(int result) {
83     if (result >= 0)
84       return true;
85     callback_.Run(result, NULL);
86     delete this;
87     return false;
88   }
89
90   std::string serial_;
91   std::string socket_name_;
92   SocketCallback callback_;
93 };
94
95 class HttpOverAdbSocket {
96  public:
97   HttpOverAdbSocket(net::StreamSocket* socket,
98                     const std::string& request,
99                     const CommandCallback& callback)
100     : socket_(socket),
101       command_callback_(callback),
102       body_pos_(0) {
103     SendRequest(request);
104   }
105
106   HttpOverAdbSocket(net::StreamSocket* socket,
107                     const std::string& request,
108                     const SocketCallback& callback)
109     : socket_(socket),
110       socket_callback_(callback),
111       body_pos_(0) {
112     SendRequest(request);
113   }
114
115  private:
116   ~HttpOverAdbSocket() {
117   }
118
119   void SendRequest(const std::string& request) {
120     scoped_refptr<net::StringIOBuffer> request_buffer =
121         new net::StringIOBuffer(request);
122
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);
129   }
130
131   void ReadResponse(int result) {
132     if (!CheckNetResultOrDie(result))
133       return;
134     scoped_refptr<net::IOBuffer> response_buffer =
135         new net::IOBuffer(kBufferSize);
136
137     result = socket_->Read(response_buffer.get(),
138                            kBufferSize,
139                            base::Bind(&HttpOverAdbSocket::OnResponseData,
140                                       base::Unretained(this),
141                                       response_buffer,
142                                       -1));
143     if (result != net::ERR_IO_PENDING)
144       OnResponseData(response_buffer, -1, result);
145   }
146
147   void OnResponseData(scoped_refptr<net::IOBuffer> response_buffer,
148                       int bytes_total,
149                       int result) {
150     if (!CheckNetResultOrDie(result))
151       return;
152     if (result == 0) {
153       CheckNetResultOrDie(net::ERR_CONNECTION_CLOSED);
154       return;
155     }
156
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);
170             return;
171           }
172         }
173       }
174
175       body_pos_ = response_.find("\r\n\r\n");
176       if (body_pos_ != std::string::npos) {
177         body_pos_ += 4;
178         bytes_total = body_pos_ + expected_length;
179       }
180     }
181
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_));
185       else
186         socket_callback_.Run(net::OK, socket_.release());
187       delete this;
188       return;
189     }
190
191     result = socket_->Read(response_buffer.get(),
192                            kBufferSize,
193                            base::Bind(&HttpOverAdbSocket::OnResponseData,
194                                       base::Unretained(this),
195                                       response_buffer,
196                                       bytes_total));
197     if (result != net::ERR_IO_PENDING)
198       OnResponseData(response_buffer, bytes_total, result);
199   }
200
201   bool CheckNetResultOrDie(int result) {
202     if (result >= 0)
203       return true;
204     if (!command_callback_.is_null())
205       command_callback_.Run(result, std::string());
206     else
207       socket_callback_.Run(result, NULL);
208     delete this;
209     return false;
210   }
211
212   scoped_ptr<net::StreamSocket> socket_;
213   std::string response_;
214   CommandCallback command_callback_;
215   SocketCallback socket_callback_;
216   size_t body_pos_;
217 };
218
219 class AdbQuerySocket : AdbClientSocket {
220  public:
221   AdbQuerySocket(int port,
222                  const std::string& query,
223                  const CommandCallback& callback)
224       : AdbClientSocket(port),
225         current_query_(0),
226         callback_(callback) {
227     if (Tokenize(query, "|", &queries_) == 0) {
228       CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT);
229       return;
230     }
231     Connect(base::Bind(&AdbQuerySocket::SendNextQuery,
232                        base::Unretained(this)));
233   }
234
235  private:
236   ~AdbQuerySocket() {
237   }
238
239   void SendNextQuery(int result) {
240     if (!CheckNetResultOrDie(result))
241       return;
242     std::string query = queries_[current_query_];
243     if (query.length() > 0xFFFF) {
244       CheckNetResultOrDie(net::ERR_MSG_TOO_BIG);
245       return;
246     }
247     bool is_void = current_query_ < queries_.size() - 1;
248     SendCommand(query, is_void,
249         base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
250   }
251
252   void OnResponse(int result, const std::string& response) {
253     if (++current_query_ < queries_.size()) {
254       SendNextQuery(net::OK);
255     } else {
256       callback_.Run(result, response);
257       delete this;
258     }
259   }
260
261   bool CheckNetResultOrDie(int result) {
262     if (result >= 0)
263       return true;
264     callback_.Run(result, std::string());
265     delete this;
266     return false;
267   }
268
269   std::vector<std::string> queries_;
270   size_t current_query_;
271   CommandCallback callback_;
272 };
273
274 }  // namespace
275
276 // static
277 void AdbClientSocket::AdbQuery(int port,
278                                const std::string& query,
279                                const CommandCallback& callback) {
280   new AdbQuerySocket(port, query, callback);
281 }
282
283 #if defined(DEBUG_DEVTOOLS)
284 static void UseTransportQueryForDesktop(const SocketCallback& callback,
285                                         net::StreamSocket* socket,
286                                         int result) {
287   callback.Run(result, socket);
288 }
289 #endif  // defined(DEBUG_DEVTOOLS)
290
291 // static
292 void AdbClientSocket::TransportQuery(int port,
293                                      const std::string& serial,
294                                      const std::string& socket_name,
295                                      const SocketCallback& callback) {
296 #if defined(DEBUG_DEVTOOLS)
297   if (serial.empty()) {
298     // Use plain socket for remote debugging on Desktop (debugging purposes).
299     net::IPAddressNumber ip_number;
300     net::ParseIPLiteralToNumber(kLocalhost, &ip_number);
301
302     int tcp_port = 0;
303     if (!base::StringToInt(socket_name, &tcp_port))
304       tcp_port = 9222;
305
306     net::AddressList address_list =
307         net::AddressList::CreateFromIPAddress(ip_number, tcp_port);
308     net::TCPClientSocket* socket = new net::TCPClientSocket(
309         address_list, NULL, net::NetLog::Source());
310     socket->Connect(base::Bind(&UseTransportQueryForDesktop, callback, socket));
311     return;
312   }
313 #endif  // defined(DEBUG_DEVTOOLS)
314   new AdbTransportSocket(port, serial, socket_name, callback);
315 }
316
317 // static
318 void AdbClientSocket::HttpQuery(net::StreamSocket* socket,
319                                 const std::string& request_path,
320                                 const CommandCallback& callback) {
321   new HttpOverAdbSocket(socket, request_path, callback);
322 }
323
324 // static
325 void AdbClientSocket::HttpQuery(net::StreamSocket* socket,
326                                 const std::string& request_path,
327                                 const SocketCallback& callback) {
328   new HttpOverAdbSocket(socket, request_path, callback);
329 }
330
331 AdbClientSocket::AdbClientSocket(int port)
332     : host_(kLocalhost), port_(port) {
333 }
334
335 AdbClientSocket::~AdbClientSocket() {
336 }
337
338 void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
339   net::IPAddressNumber ip_number;
340   if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
341     callback.Run(net::ERR_FAILED);
342     return;
343   }
344
345   net::AddressList address_list =
346       net::AddressList::CreateFromIPAddress(ip_number, port_);
347   socket_.reset(new net::TCPClientSocket(address_list, NULL,
348                                          net::NetLog::Source()));
349   int result = socket_->Connect(callback);
350   if (result != net::ERR_IO_PENDING)
351     callback.Run(result);
352 }
353
354 void AdbClientSocket::SendCommand(const std::string& command,
355                                   bool is_void,
356                                   const CommandCallback& callback) {
357   scoped_refptr<net::StringIOBuffer> request_buffer =
358       new net::StringIOBuffer(EncodeMessage(command));
359   int result = socket_->Write(request_buffer.get(),
360                               request_buffer->size(),
361                               base::Bind(&AdbClientSocket::ReadResponse,
362                                          base::Unretained(this),
363                                          callback,
364                                          is_void));
365   if (result != net::ERR_IO_PENDING)
366     ReadResponse(callback, is_void, result);
367 }
368
369 void AdbClientSocket::ReadResponse(const CommandCallback& callback,
370                                    bool is_void,
371                                    int result) {
372   if (result < 0) {
373     callback.Run(result, "IO error");
374     return;
375   }
376   scoped_refptr<net::IOBuffer> response_buffer =
377       new net::IOBuffer(kBufferSize);
378   result = socket_->Read(response_buffer.get(),
379                          kBufferSize,
380                          base::Bind(&AdbClientSocket::OnResponseHeader,
381                                     base::Unretained(this),
382                                     callback,
383                                     is_void,
384                                     response_buffer));
385   if (result != net::ERR_IO_PENDING)
386     OnResponseHeader(callback, is_void, response_buffer, result);
387 }
388
389 void AdbClientSocket::OnResponseHeader(
390     const CommandCallback& callback,
391     bool is_void,
392     scoped_refptr<net::IOBuffer> response_buffer,
393     int result) {
394   if (result <= 0) {
395     callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
396                  "IO error");
397     return;
398   }
399
400   std::string data = std::string(response_buffer->data(), result);
401   if (result < 4) {
402     callback.Run(net::ERR_FAILED, "Response is too short: " + data);
403     return;
404   }
405
406   std::string status = data.substr(0, 4);
407   if (status != kOkayResponse) {
408     callback.Run(net::ERR_FAILED, data);
409     return;
410   }
411
412   data = data.substr(4);
413
414   if (!is_void) {
415     int payload_length = 0;
416     int bytes_left = -1;
417     if (data.length() >= 4 &&
418         base::HexStringToInt(data.substr(0, 4), &payload_length)) {
419       data = data.substr(4);
420       bytes_left = payload_length - result + 8;
421     } else {
422       bytes_left = -1;
423     }
424     OnResponseData(callback, data, response_buffer, bytes_left, 0);
425   } else {
426     callback.Run(net::OK, data);
427   }
428 }
429
430 void AdbClientSocket::OnResponseData(
431     const CommandCallback& callback,
432     const std::string& response,
433     scoped_refptr<net::IOBuffer> response_buffer,
434     int bytes_left,
435     int result) {
436   if (result < 0) {
437     callback.Run(result, "IO error");
438     return;
439   }
440
441   bytes_left -= result;
442   std::string new_response =
443       response + std::string(response_buffer->data(), result);
444   if (bytes_left == 0) {
445     callback.Run(net::OK, new_response);
446     return;
447   }
448
449   // Read tail
450   result = socket_->Read(response_buffer.get(),
451                          kBufferSize,
452                          base::Bind(&AdbClientSocket::OnResponseData,
453                                     base::Unretained(this),
454                                     callback,
455                                     new_response,
456                                     response_buffer,
457                                     bytes_left));
458   if (result > 0)
459     OnResponseData(callback, new_response, response_buffer, bytes_left, result);
460   else if (result != net::ERR_IO_PENDING)
461     callback.Run(net::OK, new_response);
462 }