Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / device / port_forwarding_controller.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/port_forwarding_controller.h"
6
7 #include <algorithm>
8 #include <map>
9
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/singleton.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/threading/non_thread_safe.h"
19 #include "chrome/browser/devtools/devtools_protocol.h"
20 #include "chrome/browser/devtools/devtools_protocol_constants.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/keyed_service/content/browser_context_dependency_manager.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "net/base/address_list.h"
26 #include "net/base/io_buffer.h"
27 #include "net/base/net_errors.h"
28 #include "net/base/net_util.h"
29 #include "net/dns/host_resolver.h"
30 #include "net/socket/tcp_client_socket.h"
31
32 using content::BrowserThread;
33
34 namespace {
35
36 const int kBufferSize = 16 * 1024;
37
38 enum {
39   kStatusError = -3,
40   kStatusDisconnecting = -2,
41   kStatusConnecting = -1,
42   kStatusOK = 0,
43   // Positive values are used to count open connections.
44 };
45
46 namespace tethering = ::chrome::devtools::Tethering;
47
48 static const char kDevToolsRemoteBrowserTarget[] = "/devtools/browser";
49 const int kMinVersionPortForwarding = 28;
50
51 class SocketTunnel : public base::NonThreadSafe {
52  public:
53   typedef base::Callback<void(int)> CounterCallback;
54
55   static void StartTunnel(const std::string& host,
56                           int port,
57                           const CounterCallback& callback,
58                           int result,
59                           scoped_ptr<net::StreamSocket> socket) {
60     if (result < 0)
61       return;
62     SocketTunnel* tunnel = new SocketTunnel(callback);
63     tunnel->Start(socket.Pass(), host, port);
64   }
65
66  private:
67   explicit SocketTunnel(const CounterCallback& callback)
68       : pending_writes_(0),
69         pending_destruction_(false),
70         callback_(callback),
71         about_to_destroy_(false) {
72     callback_.Run(1);
73   }
74
75   void Start(scoped_ptr<net::StreamSocket> socket,
76              const std::string& host, int port) {
77     remote_socket_.swap(socket);
78
79     host_resolver_ = net::HostResolver::CreateDefaultResolver(NULL);
80     net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port));
81     int result = host_resolver_->Resolve(
82         request_info,
83         net::DEFAULT_PRIORITY,
84         &address_list_,
85         base::Bind(&SocketTunnel::OnResolved, base::Unretained(this)),
86         NULL,
87         net::BoundNetLog());
88     if (result != net::ERR_IO_PENDING)
89       OnResolved(result);
90   }
91
92   void OnResolved(int result) {
93     if (result < 0) {
94       SelfDestruct();
95       return;
96     }
97
98     host_socket_.reset(new net::TCPClientSocket(address_list_, NULL,
99                                                 net::NetLog::Source()));
100     result = host_socket_->Connect(base::Bind(&SocketTunnel::OnConnected,
101                                               base::Unretained(this)));
102     if (result != net::ERR_IO_PENDING)
103       OnConnected(result);
104   }
105
106   ~SocketTunnel() {
107     about_to_destroy_ = true;
108     if (host_socket_)
109       host_socket_->Disconnect();
110     if (remote_socket_)
111       remote_socket_->Disconnect();
112     callback_.Run(-1);
113   }
114
115   void OnConnected(int result) {
116     if (result < 0) {
117       SelfDestruct();
118       return;
119     }
120
121     ++pending_writes_; // avoid SelfDestruct in first Pump
122     Pump(host_socket_.get(), remote_socket_.get());
123     --pending_writes_;
124     if (pending_destruction_) {
125       SelfDestruct();
126     } else {
127       Pump(remote_socket_.get(), host_socket_.get());
128     }
129   }
130
131   void Pump(net::StreamSocket* from, net::StreamSocket* to) {
132     scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
133     int result = from->Read(
134         buffer.get(),
135         kBufferSize,
136         base::Bind(
137             &SocketTunnel::OnRead, base::Unretained(this), from, to, buffer));
138     if (result != net::ERR_IO_PENDING)
139       OnRead(from, to, buffer, result);
140   }
141
142   void OnRead(net::StreamSocket* from,
143               net::StreamSocket* to,
144               scoped_refptr<net::IOBuffer> buffer,
145               int result) {
146     if (result <= 0) {
147       SelfDestruct();
148       return;
149     }
150
151     int total = result;
152     scoped_refptr<net::DrainableIOBuffer> drainable =
153         new net::DrainableIOBuffer(buffer.get(), total);
154
155     ++pending_writes_;
156     result = to->Write(drainable.get(),
157                        total,
158                        base::Bind(&SocketTunnel::OnWritten,
159                                   base::Unretained(this),
160                                   drainable,
161                                   from,
162                                   to));
163     if (result != net::ERR_IO_PENDING)
164       OnWritten(drainable, from, to, result);
165   }
166
167   void OnWritten(scoped_refptr<net::DrainableIOBuffer> drainable,
168                  net::StreamSocket* from,
169                  net::StreamSocket* to,
170                  int result) {
171     --pending_writes_;
172     if (result < 0) {
173       SelfDestruct();
174       return;
175     }
176
177     drainable->DidConsume(result);
178     if (drainable->BytesRemaining() > 0) {
179       ++pending_writes_;
180       result = to->Write(drainable.get(),
181                          drainable->BytesRemaining(),
182                          base::Bind(&SocketTunnel::OnWritten,
183                                     base::Unretained(this),
184                                     drainable,
185                                     from,
186                                     to));
187       if (result != net::ERR_IO_PENDING)
188         OnWritten(drainable, from, to, result);
189       return;
190     }
191
192     if (pending_destruction_) {
193       SelfDestruct();
194       return;
195     }
196     Pump(from, to);
197   }
198
199   void SelfDestruct() {
200     // In case one of the connections closes, we could get here
201     // from another one due to Disconnect firing back on all
202     // read callbacks.
203     if (about_to_destroy_)
204       return;
205     if (pending_writes_ > 0) {
206       pending_destruction_ = true;
207       return;
208     }
209     delete this;
210   }
211
212   scoped_ptr<net::StreamSocket> remote_socket_;
213   scoped_ptr<net::StreamSocket> host_socket_;
214   scoped_ptr<net::HostResolver> host_resolver_;
215   net::AddressList address_list_;
216   int pending_writes_;
217   bool pending_destruction_;
218   CounterCallback callback_;
219   bool about_to_destroy_;
220 };
221
222 typedef DevToolsAndroidBridge::RemoteBrowser::ParsedVersion ParsedVersion;
223
224 static bool IsVersionLower(const ParsedVersion& left,
225                            const ParsedVersion& right) {
226   return std::lexicographical_compare(
227     left.begin(), left.end(), right.begin(), right.end());
228 }
229
230 static bool IsPortForwardingSupported(const ParsedVersion& version) {
231   return !version.empty() && version[0] >= kMinVersionPortForwarding;
232 }
233
234 static scoped_refptr<DevToolsAndroidBridge::RemoteBrowser>
235 FindBestBrowserForTethering(
236     const DevToolsAndroidBridge::RemoteBrowsers browsers) {
237   scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> best_browser;
238   ParsedVersion newest_version;
239   for (DevToolsAndroidBridge::RemoteBrowsers::const_iterator it =
240       browsers.begin(); it != browsers.end(); ++it) {
241     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser = *it;
242     ParsedVersion current_version = browser->GetParsedVersion();
243     if (IsPortForwardingSupported(current_version) &&
244         IsVersionLower(newest_version, current_version)) {
245       best_browser = browser;
246       newest_version = current_version;
247     }
248   }
249   return best_browser;
250 }
251
252 }  // namespace
253
254 class PortForwardingController::Connection
255     : public AndroidDeviceManager::AndroidWebSocket::Delegate {
256  public:
257   Connection(PortForwardingController* controller,
258              scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
259              const ForwardingMap& forwarding_map);
260   ~Connection() override;
261
262   const PortStatusMap& GetPortStatusMap();
263
264   void UpdateForwardingMap(const ForwardingMap& new_forwarding_map);
265
266   scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser() {
267     return browser_;
268   }
269
270  private:
271   friend struct content::BrowserThread::DeleteOnThread<
272       content::BrowserThread::UI>;
273   friend class base::DeleteHelper<Connection>;
274
275   typedef std::map<int, std::string> ForwardingMap;
276   typedef base::Callback<void(PortStatus)> CommandCallback;
277   typedef std::map<int, CommandCallback> CommandCallbackMap;
278
279   void SerializeChanges(const std::string& method,
280                         const ForwardingMap& old_map,
281                         const ForwardingMap& new_map);
282
283   void SendCommand(const std::string& method, int port);
284   bool ProcessResponse(const std::string& json);
285
286   void ProcessBindResponse(int port, PortStatus status);
287   void ProcessUnbindResponse(int port, PortStatus status);
288
289   static void UpdateSocketCountOnHandlerThread(
290       base::WeakPtr<Connection> weak_connection, int port, int increment);
291   void UpdateSocketCount(int port, int increment);
292
293   // DevToolsAndroidBridge::AndroidWebSocket::Delegate implementation:
294   void OnSocketOpened() override;
295   void OnFrameRead(const std::string& message) override;
296   void OnSocketClosed() override;
297
298   PortForwardingController* controller_;
299   scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
300   scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
301   int command_id_;
302   bool connected_;
303   ForwardingMap forwarding_map_;
304   CommandCallbackMap pending_responses_;
305   PortStatusMap port_status_;
306   base::WeakPtrFactory<Connection> weak_factory_;
307
308   DISALLOW_COPY_AND_ASSIGN(Connection);
309 };
310
311 PortForwardingController::Connection::Connection(
312     PortForwardingController* controller,
313     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
314     const ForwardingMap& forwarding_map)
315     : controller_(controller),
316       browser_(browser),
317       command_id_(0),
318       connected_(false),
319       forwarding_map_(forwarding_map),
320       weak_factory_(this) {
321   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
322   controller_->registry_[browser->serial()] = this;
323   scoped_refptr<AndroidDeviceManager::Device> device(
324       controller_->bridge_->FindDevice(browser->serial()));
325   DCHECK(device.get());
326   web_socket_.reset(
327       device->CreateWebSocket(browser->socket(),
328                               kDevToolsRemoteBrowserTarget, this));
329 }
330
331 PortForwardingController::Connection::~Connection() {
332   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
333   DCHECK(controller_->registry_.find(browser_->serial()) !=
334          controller_->registry_.end());
335   controller_->registry_.erase(browser_->serial());
336 }
337
338 void PortForwardingController::Connection::UpdateForwardingMap(
339     const ForwardingMap& new_forwarding_map) {
340   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341   if (connected_) {
342     SerializeChanges(tethering::unbind::kName,
343         new_forwarding_map, forwarding_map_);
344     SerializeChanges(tethering::bind::kName,
345         forwarding_map_, new_forwarding_map);
346   }
347   forwarding_map_ = new_forwarding_map;
348 }
349
350 void PortForwardingController::Connection::SerializeChanges(
351     const std::string& method,
352     const ForwardingMap& old_map,
353     const ForwardingMap& new_map) {
354   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355   for (ForwardingMap::const_iterator new_it(new_map.begin());
356       new_it != new_map.end(); ++new_it) {
357     int port = new_it->first;
358     const std::string& location = new_it->second;
359     ForwardingMap::const_iterator old_it = old_map.find(port);
360     if (old_it != old_map.end() && old_it->second == location)
361       continue;  // The port points to the same location in both configs, skip.
362
363     SendCommand(method, port);
364   }
365 }
366
367 void PortForwardingController::Connection::SendCommand(
368     const std::string& method, int port) {
369   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370   base::DictionaryValue params;
371   if (method == tethering::bind::kName) {
372     params.SetInteger(tethering::bind::kParamPort, port);
373   } else {
374     DCHECK_EQ(tethering::unbind::kName, method);
375     params.SetInteger(tethering::unbind::kParamPort, port);
376   }
377   DevToolsProtocol::Command command(++command_id_, method, &params);
378
379   if (method == tethering::bind::kName) {
380     pending_responses_[command.id()] =
381         base::Bind(&Connection::ProcessBindResponse,
382                    base::Unretained(this), port);
383 #if defined(DEBUG_DEVTOOLS)
384     port_status_[port] = kStatusConnecting;
385 #endif  // defined(DEBUG_DEVTOOLS)
386   } else {
387     PortStatusMap::iterator it = port_status_.find(port);
388     if (it != port_status_.end() && it->second == kStatusError) {
389       // The bind command failed on this port, do not attempt unbind.
390       port_status_.erase(it);
391       return;
392     }
393
394     pending_responses_[command.id()] =
395         base::Bind(&Connection::ProcessUnbindResponse,
396                    base::Unretained(this), port);
397 #if defined(DEBUG_DEVTOOLS)
398     port_status_[port] = kStatusDisconnecting;
399 #endif  // defined(DEBUG_DEVTOOLS)
400   }
401
402   web_socket_->SendFrame(command.Serialize());
403 }
404
405 bool PortForwardingController::Connection::ProcessResponse(
406     const std::string& message) {
407   scoped_ptr<DevToolsProtocol::Response> response(
408       DevToolsProtocol::ParseResponse(message));
409   if (!response)
410     return false;
411
412   CommandCallbackMap::iterator it = pending_responses_.find(response->id());
413   if (it == pending_responses_.end())
414     return false;
415
416   it->second.Run(response->error_code() ? kStatusError : kStatusOK);
417   pending_responses_.erase(it);
418   return true;
419 }
420
421 void PortForwardingController::Connection::ProcessBindResponse(
422     int port, PortStatus status) {
423   port_status_[port] = status;
424 }
425
426 void PortForwardingController::Connection::ProcessUnbindResponse(
427     int port, PortStatus status) {
428   PortStatusMap::iterator it = port_status_.find(port);
429   if (it == port_status_.end())
430     return;
431   if (status == kStatusError)
432     it->second = status;
433   else
434     port_status_.erase(it);
435 }
436
437 // static
438 void PortForwardingController::Connection::UpdateSocketCountOnHandlerThread(
439     base::WeakPtr<Connection> weak_connection, int port, int increment) {
440   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
441      base::Bind(&Connection::UpdateSocketCount,
442                 weak_connection, port, increment));
443 }
444
445 void PortForwardingController::Connection::UpdateSocketCount(
446     int port, int increment) {
447 #if defined(DEBUG_DEVTOOLS)
448   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
449   PortStatusMap::iterator it = port_status_.find(port);
450   if (it == port_status_.end())
451     return;
452   if (it->second < 0 || (it->second == 0 && increment < 0))
453     return;
454   it->second += increment;
455 #endif  // defined(DEBUG_DEVTOOLS)
456 }
457
458 const PortForwardingController::PortStatusMap&
459 PortForwardingController::Connection::GetPortStatusMap() {
460   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
461   return port_status_;
462 }
463
464 void PortForwardingController::Connection::OnSocketOpened() {
465   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
466   connected_ = true;
467   SerializeChanges(tethering::bind::kName, ForwardingMap(), forwarding_map_);
468 }
469
470 void PortForwardingController::Connection::OnSocketClosed() {
471   delete this;
472 }
473
474 void PortForwardingController::Connection::OnFrameRead(
475     const std::string& message) {
476   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
477   if (ProcessResponse(message))
478     return;
479
480   scoped_ptr<DevToolsProtocol::Notification> notification(
481       DevToolsProtocol::ParseNotification(message));
482   if (!notification)
483     return;
484
485   if (notification->method() != tethering::accepted::kName)
486     return;
487
488   base::DictionaryValue* params = notification->params();
489   if (!params)
490     return;
491
492   int port;
493   std::string connection_id;
494   if (!params->GetInteger(tethering::accepted::kParamPort, &port) ||
495       !params->GetString(tethering::accepted::kParamConnectionId,
496                          &connection_id))
497     return;
498
499   std::map<int, std::string>::iterator it = forwarding_map_.find(port);
500   if (it == forwarding_map_.end())
501     return;
502
503   std::string location = it->second;
504   std::vector<std::string> tokens;
505   Tokenize(location, ":", &tokens);
506   int destination_port = 0;
507   if (tokens.size() != 2 || !base::StringToInt(tokens[1], &destination_port))
508     return;
509   std::string destination_host = tokens[0];
510
511   SocketTunnel::CounterCallback callback =
512       base::Bind(&Connection::UpdateSocketCountOnHandlerThread,
513                  weak_factory_.GetWeakPtr(), port);
514
515   scoped_refptr<AndroidDeviceManager::Device> device(
516       controller_->bridge_->FindDevice(browser_->serial()));
517   DCHECK(device.get());
518   device->OpenSocket(
519       connection_id.c_str(),
520       base::Bind(&SocketTunnel::StartTunnel,
521                  destination_host,
522                  destination_port,
523                  callback));
524 }
525
526 PortForwardingController::PortForwardingController(
527     Profile* profile,
528     DevToolsAndroidBridge* bridge)
529     : profile_(profile),
530       bridge_(bridge),
531       pref_service_(profile->GetPrefs()) {
532   pref_change_registrar_.Init(pref_service_);
533   base::Closure callback = base::Bind(
534       &PortForwardingController::OnPrefsChange, base::Unretained(this));
535   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled, callback);
536   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig, callback);
537   OnPrefsChange();
538 }
539
540 PortForwardingController::~PortForwardingController() {}
541
542 PortForwardingController::ForwardingStatus
543 PortForwardingController::DeviceListChanged(
544     const DevToolsAndroidBridge::RemoteDevices& devices) {
545   ForwardingStatus status;
546   if (forwarding_map_.empty())
547     return status;
548
549   for (const auto& device : devices) {
550     if (!device->is_connected())
551       continue;
552     Registry::iterator rit = registry_.find(device->serial());
553     if (rit == registry_.end()) {
554       scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser(
555           FindBestBrowserForTethering(device->browsers()));
556       if (browser.get())
557         new Connection(this, browser, forwarding_map_);
558     } else {
559       status.push_back(std::make_pair(rit->second->browser(),
560                                       rit->second->GetPortStatusMap()));
561     }
562   }
563   return status;
564 }
565
566 void PortForwardingController::OnPrefsChange() {
567   forwarding_map_.clear();
568
569   if (pref_service_->GetBoolean(prefs::kDevToolsPortForwardingEnabled)) {
570     const base::DictionaryValue* dict =
571         pref_service_->GetDictionary(prefs::kDevToolsPortForwardingConfig);
572     for (base::DictionaryValue::Iterator it(*dict);
573          !it.IsAtEnd(); it.Advance()) {
574       int port_num;
575       std::string location;
576       if (base::StringToInt(it.key(), &port_num) &&
577           dict->GetString(it.key(), &location))
578         forwarding_map_[port_num] = location;
579     }
580   }
581
582   if (!forwarding_map_.empty()) {
583     UpdateConnections();
584   } else {
585     std::vector<Connection*> registry_copy;
586     for (Registry::iterator it = registry_.begin();
587         it != registry_.end(); ++it) {
588       registry_copy.push_back(it->second);
589     }
590     STLDeleteElements(&registry_copy);
591   }
592 }
593
594 void PortForwardingController::UpdateConnections() {
595   for (Registry::iterator it = registry_.begin(); it != registry_.end(); ++it)
596     it->second->UpdateForwardingMap(forwarding_map_);
597 }