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