Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / device / adb / adb_client_socket.cc
1 // Copyright 2014 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/device/adb/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/net_errors.h"
13 #include "net/base/net_util.h"
14 #include "net/socket/tcp_client_socket.h"
15
16 namespace {
17
18 const int kBufferSize = 16 * 1024;
19 const char kOkayResponse[] = "OKAY";
20 const char kHostTransportCommand[] = "host:transport:%s";
21 const char kLocalhost[] = "127.0.0.1";
22
23 typedef base::Callback<void(int, const std::string&)> CommandCallback;
24 typedef base::Callback<void(int, net::StreamSocket*)> SocketCallback;
25
26 std::string EncodeMessage(const std::string& message) {
27   static const char kHexChars[] = "0123456789ABCDEF";
28
29   size_t length = message.length();
30   std::string result(4, '\0');
31   char b = reinterpret_cast<const char*>(&length)[1];
32   result[0] = kHexChars[(b >> 4) & 0xf];
33   result[1] = kHexChars[b & 0xf];
34   b = reinterpret_cast<const char*>(&length)[0];
35   result[2] = kHexChars[(b >> 4) & 0xf];
36   result[3] = kHexChars[b & 0xf];
37   return result + message;
38 }
39
40 class AdbTransportSocket : public AdbClientSocket {
41  public:
42   AdbTransportSocket(int port,
43                      const std::string& serial,
44                      const std::string& socket_name,
45                      const SocketCallback& callback)
46     : AdbClientSocket(port),
47       serial_(serial),
48       socket_name_(socket_name),
49       callback_(callback) {
50     Connect(base::Bind(&AdbTransportSocket::OnConnected,
51                        base::Unretained(this)));
52   }
53
54  private:
55   ~AdbTransportSocket() {}
56
57   void OnConnected(int result) {
58     if (!CheckNetResultOrDie(result))
59       return;
60     SendCommand(base::StringPrintf(kHostTransportCommand, serial_.c_str()),
61         true, base::Bind(&AdbTransportSocket::SendLocalAbstract,
62                          base::Unretained(this)));
63   }
64
65   void SendLocalAbstract(int result, const std::string& response) {
66     if (!CheckNetResultOrDie(result))
67       return;
68     SendCommand(socket_name_, true,
69                 base::Bind(&AdbTransportSocket::OnSocketAvailable,
70                            base::Unretained(this)));
71   }
72
73   void OnSocketAvailable(int result, const std::string& response) {
74     if (!CheckNetResultOrDie(result))
75       return;
76     callback_.Run(net::OK, socket_.release());
77     delete this;
78   }
79
80   bool CheckNetResultOrDie(int result) {
81     if (result >= 0)
82       return true;
83     callback_.Run(result, NULL);
84     delete this;
85     return false;
86   }
87
88   std::string serial_;
89   std::string socket_name_;
90   SocketCallback callback_;
91 };
92
93 class AdbQuerySocket : AdbClientSocket {
94  public:
95   AdbQuerySocket(int port,
96                  const std::string& query,
97                  const CommandCallback& callback)
98       : AdbClientSocket(port),
99         current_query_(0),
100         callback_(callback) {
101     if (Tokenize(query, "|", &queries_) == 0) {
102       CheckNetResultOrDie(net::ERR_INVALID_ARGUMENT);
103       return;
104     }
105     Connect(base::Bind(&AdbQuerySocket::SendNextQuery,
106                        base::Unretained(this)));
107   }
108
109  private:
110   ~AdbQuerySocket() {
111   }
112
113   void SendNextQuery(int result) {
114     if (!CheckNetResultOrDie(result))
115       return;
116     std::string query = queries_[current_query_];
117     if (query.length() > 0xFFFF) {
118       CheckNetResultOrDie(net::ERR_MSG_TOO_BIG);
119       return;
120     }
121     bool is_void = current_query_ < queries_.size() - 1;
122     SendCommand(query, is_void,
123         base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
124   }
125
126   void OnResponse(int result, const std::string& response) {
127     if (++current_query_ < queries_.size()) {
128       SendNextQuery(net::OK);
129     } else {
130       callback_.Run(result, response);
131       delete this;
132     }
133   }
134
135   bool CheckNetResultOrDie(int result) {
136     if (result >= 0)
137       return true;
138     callback_.Run(result, std::string());
139     delete this;
140     return false;
141   }
142
143   std::vector<std::string> queries_;
144   size_t current_query_;
145   CommandCallback callback_;
146 };
147
148 }  // namespace
149
150 // static
151 void AdbClientSocket::AdbQuery(int port,
152                                const std::string& query,
153                                const CommandCallback& callback) {
154   new AdbQuerySocket(port, query, callback);
155 }
156
157 // static
158 void AdbClientSocket::TransportQuery(int port,
159                                      const std::string& serial,
160                                      const std::string& socket_name,
161                                      const SocketCallback& callback) {
162   new AdbTransportSocket(port, serial, socket_name, callback);
163 }
164
165 AdbClientSocket::AdbClientSocket(int port)
166     : host_(kLocalhost), port_(port) {
167 }
168
169 AdbClientSocket::~AdbClientSocket() {
170 }
171
172 void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
173   net::IPAddressNumber ip_number;
174   if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
175     callback.Run(net::ERR_FAILED);
176     return;
177   }
178
179   net::AddressList address_list =
180       net::AddressList::CreateFromIPAddress(ip_number, port_);
181   socket_.reset(new net::TCPClientSocket(address_list, NULL,
182                                          net::NetLog::Source()));
183   int result = socket_->Connect(callback);
184   if (result != net::ERR_IO_PENDING)
185     callback.Run(result);
186 }
187
188 void AdbClientSocket::SendCommand(const std::string& command,
189                                   bool is_void,
190                                   const CommandCallback& callback) {
191   scoped_refptr<net::StringIOBuffer> request_buffer =
192       new net::StringIOBuffer(EncodeMessage(command));
193   int result = socket_->Write(request_buffer.get(),
194                               request_buffer->size(),
195                               base::Bind(&AdbClientSocket::ReadResponse,
196                                          base::Unretained(this),
197                                          callback,
198                                          is_void));
199   if (result != net::ERR_IO_PENDING)
200     ReadResponse(callback, is_void, result);
201 }
202
203 void AdbClientSocket::ReadResponse(const CommandCallback& callback,
204                                    bool is_void,
205                                    int result) {
206   if (result < 0) {
207     callback.Run(result, "IO error");
208     return;
209   }
210   scoped_refptr<net::IOBuffer> response_buffer =
211       new net::IOBuffer(kBufferSize);
212   result = socket_->Read(response_buffer.get(),
213                          kBufferSize,
214                          base::Bind(&AdbClientSocket::OnResponseHeader,
215                                     base::Unretained(this),
216                                     callback,
217                                     is_void,
218                                     response_buffer));
219   if (result != net::ERR_IO_PENDING)
220     OnResponseHeader(callback, is_void, response_buffer, result);
221 }
222
223 void AdbClientSocket::OnResponseHeader(
224     const CommandCallback& callback,
225     bool is_void,
226     scoped_refptr<net::IOBuffer> response_buffer,
227     int result) {
228   if (result <= 0) {
229     callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
230                  "IO error");
231     return;
232   }
233
234   std::string data = std::string(response_buffer->data(), result);
235   if (result < 4) {
236     callback.Run(net::ERR_FAILED, "Response is too short: " + data);
237     return;
238   }
239
240   std::string status = data.substr(0, 4);
241   if (status != kOkayResponse) {
242     callback.Run(net::ERR_FAILED, data);
243     return;
244   }
245
246   data = data.substr(4);
247
248   if (!is_void) {
249     int payload_length = 0;
250     int bytes_left = -1;
251     if (data.length() >= 4 &&
252         base::HexStringToInt(data.substr(0, 4), &payload_length)) {
253       data = data.substr(4);
254       bytes_left = payload_length - result + 8;
255     } else {
256       bytes_left = -1;
257     }
258     OnResponseData(callback, data, response_buffer, bytes_left, 0);
259   } else {
260     callback.Run(net::OK, data);
261   }
262 }
263
264 void AdbClientSocket::OnResponseData(
265     const CommandCallback& callback,
266     const std::string& response,
267     scoped_refptr<net::IOBuffer> response_buffer,
268     int bytes_left,
269     int result) {
270   if (result < 0) {
271     callback.Run(result, "IO error");
272     return;
273   }
274
275   bytes_left -= result;
276   std::string new_response =
277       response + std::string(response_buffer->data(), result);
278   if (bytes_left == 0) {
279     callback.Run(net::OK, new_response);
280     return;
281   }
282
283   // Read tail
284   result = socket_->Read(response_buffer.get(),
285                          kBufferSize,
286                          base::Bind(&AdbClientSocket::OnResponseData,
287                                     base::Unretained(this),
288                                     callback,
289                                     new_response,
290                                     response_buffer,
291                                     bytes_left));
292   if (result > 0)
293     OnResponseData(callback, new_response, response_buffer, bytes_left, result);
294   else if (result != net::ERR_IO_PENDING)
295     callback.Run(net::OK, new_response);
296 }