Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / port_forwarding_controller.cc
1 // Copyright 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/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 "chrome/browser/devtools/adb_client_socket.h"
19 #include "chrome/browser/devtools/adb_web_socket.h"
20 #include "chrome/browser/devtools/devtools_protocol.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/net_errors.h"
27 #include "net/base/net_util.h"
28 #include "net/dns/host_resolver.h"
29 #include "net/socket/tcp_client_socket.h"
30
31 using content::BrowserThread;
32
33 namespace {
34
35 const int kBufferSize = 16 * 1024;
36
37 enum {
38   kStatusError = -3,
39   kStatusDisconnecting = -2,
40   kStatusConnecting = -1,
41   kStatusOK = 0,
42   // Positive values are used to count open connections.
43 };
44
45 static const char kPortAttribute[] = "port";
46 static const char kConnectionIdAttribute[] = "connectionId";
47 static const char kTetheringAccepted[] = "Tethering.accepted";
48 static const char kTetheringBind[] = "Tethering.bind";
49 static const char kTetheringUnbind[] = "Tethering.unbind";
50
51 static const char kDevToolsRemoteBrowserTarget[] = "/devtools/browser";
52 const int kMinVersionPortForwarding = 28;
53
54 class SocketTunnel {
55  public:
56   typedef base::Callback<void(int)> CounterCallback;
57
58   SocketTunnel(const std::string& location, const CounterCallback& callback)
59       : location_(location),
60         pending_writes_(0),
61         pending_destruction_(false),
62         callback_(callback),
63         about_to_destroy_(false) {
64     callback_.Run(1);
65   }
66
67   void Start(int result, net::StreamSocket* socket) {
68     if (result < 0) {
69       SelfDestruct();
70       return;
71     }
72     remote_socket_.reset(socket);
73
74     std::vector<std::string> tokens;
75     Tokenize(location_, ":", &tokens);
76     int port = 0;
77     if (tokens.size() != 2 || !base::StringToInt(tokens[1], &port)) {
78       SelfDestruct();
79       return;
80     }
81
82     host_resolver_ = net::HostResolver::CreateDefaultResolver(NULL);
83     net::HostResolver::RequestInfo request_info(
84         net::HostPortPair(tokens[0], port));
85     result = host_resolver_->Resolve(
86         request_info,
87         net::DEFAULT_PRIORITY,
88         &address_list_,
89         base::Bind(&SocketTunnel::OnResolved, base::Unretained(this)),
90         NULL,
91         net::BoundNetLog());
92     if (result != net::ERR_IO_PENDING)
93       OnResolved(result);
94   }
95
96  private:
97   void OnResolved(int result) {
98     if (result < 0) {
99       SelfDestruct();
100       return;
101     }
102
103     host_socket_.reset(new net::TCPClientSocket(address_list_, NULL,
104                                                 net::NetLog::Source()));
105     result = host_socket_->Connect(base::Bind(&SocketTunnel::OnConnected,
106                                               base::Unretained(this)));
107     if (result != net::ERR_IO_PENDING)
108       OnConnected(result);
109   }
110
111   ~SocketTunnel() {
112     about_to_destroy_ = true;
113     if (host_socket_)
114       host_socket_->Disconnect();
115     if (remote_socket_)
116       remote_socket_->Disconnect();
117     callback_.Run(-1);
118   }
119
120   void OnConnected(int result) {
121     if (result < 0) {
122       SelfDestruct();
123       return;
124     }
125
126     Pump(host_socket_.get(), remote_socket_.get());
127     Pump(remote_socket_.get(), host_socket_.get());
128   }
129
130   void Pump(net::StreamSocket* from, net::StreamSocket* to) {
131     scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize);
132     int result = from->Read(
133         buffer.get(),
134         kBufferSize,
135         base::Bind(
136             &SocketTunnel::OnRead, base::Unretained(this), from, to, buffer));
137     if (result != net::ERR_IO_PENDING)
138       OnRead(from, to, buffer, result);
139   }
140
141   void OnRead(net::StreamSocket* from,
142               net::StreamSocket* to,
143               scoped_refptr<net::IOBuffer> buffer,
144               int result) {
145     if (result <= 0) {
146       SelfDestruct();
147       return;
148     }
149
150     int total = result;
151     scoped_refptr<net::DrainableIOBuffer> drainable =
152         new net::DrainableIOBuffer(buffer.get(), total);
153
154     ++pending_writes_;
155     result = to->Write(drainable.get(),
156                        total,
157                        base::Bind(&SocketTunnel::OnWritten,
158                                   base::Unretained(this),
159                                   drainable,
160                                   from,
161                                   to));
162     if (result != net::ERR_IO_PENDING)
163       OnWritten(drainable, from, to, result);
164   }
165
166   void OnWritten(scoped_refptr<net::DrainableIOBuffer> drainable,
167                  net::StreamSocket* from,
168                  net::StreamSocket* to,
169                  int result) {
170     --pending_writes_;
171     if (result < 0) {
172       SelfDestruct();
173       return;
174     }
175
176     drainable->DidConsume(result);
177     if (drainable->BytesRemaining() > 0) {
178       ++pending_writes_;
179       result = to->Write(drainable.get(),
180                          drainable->BytesRemaining(),
181                          base::Bind(&SocketTunnel::OnWritten,
182                                     base::Unretained(this),
183                                     drainable,
184                                     from,
185                                     to));
186       if (result != net::ERR_IO_PENDING)
187         OnWritten(drainable, from, to, result);
188       return;
189     }
190
191     if (pending_destruction_) {
192       SelfDestruct();
193       return;
194     }
195     Pump(from, to);
196   }
197
198   void SelfDestruct() {
199     // In case one of the connections closes, we could get here
200     // from another one due to Disconnect firing back on all
201     // read callbacks.
202     if (about_to_destroy_)
203       return;
204     if (pending_writes_ > 0) {
205       pending_destruction_ = true;
206       return;
207     }
208     delete this;
209   }
210
211   std::string location_;
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 DevToolsAdbBridge::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 std::string FindBestSocketForTethering(
235     const DevToolsAdbBridge::RemoteBrowsers browsers) {
236   std::string socket;
237   ParsedVersion newest_version;
238   for (DevToolsAdbBridge::RemoteBrowsers::const_iterator it = browsers.begin();
239        it != browsers.end(); ++it) {
240     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = *it;
241     ParsedVersion current_version = browser->GetParsedVersion();
242     if (browser->IsChrome() &&
243         IsPortForwardingSupported(current_version) &&
244         IsVersionLower(newest_version, current_version)) {
245       socket = browser->socket();
246       newest_version = current_version;
247     }
248   }
249   return socket;
250 }
251
252 }  // namespace
253
254 class PortForwardingController::Connection
255     : public AdbWebSocket::Delegate,
256       public base::RefCountedThreadSafe<
257           Connection,
258           content::BrowserThread::DeleteOnUIThread> {
259  public:
260   Connection(Registry* registry,
261              scoped_refptr<AndroidDevice> device,
262              const std::string& socket,
263              scoped_refptr<RefCountedAdbThread> adb_thread,
264              PrefService* pref_service);
265
266   const PortStatusMap& GetPortStatusMap();
267
268   void Shutdown();
269
270  private:
271   friend struct content::BrowserThread::DeleteOnThread<
272       content::BrowserThread::UI>;
273   friend class base::DeleteHelper<Connection>;
274
275   virtual ~Connection();
276
277   typedef std::map<int, std::string> ForwardingMap;
278
279   typedef base::Callback<void(PortStatus)> CommandCallback;
280   typedef std::map<int, CommandCallback> CommandCallbackMap;
281
282   void OnPrefsChange();
283
284   void ChangeForwardingMap(ForwardingMap map);
285
286   void SerializeChanges(const std::string& method,
287                         const ForwardingMap& old_map,
288                         const ForwardingMap& new_map);
289
290   void SendCommand(const std::string& method, int port);
291   bool ProcessResponse(const std::string& json);
292
293   void ProcessBindResponse(int port, PortStatus status);
294   void ProcessUnbindResponse(int port, PortStatus status);
295   void UpdateSocketCount(int port, int increment);
296   void UpdatePortStatusMap();
297   void UpdatePortStatusMapOnUIThread(const PortStatusMap& status_map);
298
299   // AdbWebSocket::Delegate implementation:
300   virtual void OnSocketOpened() OVERRIDE;
301   virtual void OnFrameRead(const std::string& message) OVERRIDE;
302   virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
303   virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE;
304
305   PortForwardingController::Registry* registry_;
306   scoped_refptr<AndroidDevice> device_;
307   scoped_refptr<RefCountedAdbThread> adb_thread_;
308   PrefChangeRegistrar pref_change_registrar_;
309   scoped_refptr<AdbWebSocket> web_socket_;
310   int command_id_;
311   ForwardingMap forwarding_map_;
312   CommandCallbackMap pending_responses_;
313   PortStatusMap port_status_;
314   PortStatusMap port_status_on_ui_thread_;
315
316   DISALLOW_COPY_AND_ASSIGN(Connection);
317 };
318
319 PortForwardingController::Connection::Connection(
320     Registry* registry,
321     scoped_refptr<AndroidDevice> device,
322     const std::string& socket,
323     scoped_refptr<RefCountedAdbThread> adb_thread,
324     PrefService* pref_service)
325     : registry_(registry),
326       device_(device),
327       adb_thread_(adb_thread),
328       command_id_(0) {
329   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
330   pref_change_registrar_.Init(pref_service);
331   (*registry_)[device_->serial()] = this;
332   web_socket_ = new AdbWebSocket(
333       device, socket, kDevToolsRemoteBrowserTarget,
334       adb_thread_->message_loop(), this);
335   AddRef();  // Balanced in OnSocketClosed();
336 }
337
338 void PortForwardingController::Connection::Shutdown() {
339   registry_ = NULL;
340   // This will have no effect if the socket is not connected yet.
341   web_socket_->Disconnect();
342 }
343
344 PortForwardingController::Connection::~Connection() {
345   if (registry_) {
346     DCHECK(registry_->find(device_->serial()) != registry_->end());
347     registry_->erase(device_->serial());
348   }
349 }
350
351 void PortForwardingController::Connection::OnPrefsChange() {
352   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
353
354   ForwardingMap new_forwarding_map;
355
356   PrefService* pref_service = pref_change_registrar_.prefs();
357   const base::DictionaryValue* dict =
358       pref_service->GetDictionary(prefs::kDevToolsPortForwardingConfig);
359   for (base::DictionaryValue::Iterator it(*dict);
360        !it.IsAtEnd(); it.Advance()) {
361     int port_num;
362     std::string location;
363     if (base::StringToInt(it.key(), &port_num) &&
364         dict->GetString(it.key(), &location))
365       new_forwarding_map[port_num] = location;
366   }
367
368   adb_thread_->message_loop()->PostTask(
369       FROM_HERE,
370       base::Bind(&Connection::ChangeForwardingMap,
371                  this, new_forwarding_map));
372 }
373
374 void PortForwardingController::Connection::ChangeForwardingMap(
375     ForwardingMap new_forwarding_map) {
376   DCHECK_EQ(base::MessageLoop::current(), adb_thread_->message_loop());
377
378   SerializeChanges(kTetheringUnbind, new_forwarding_map, forwarding_map_);
379   SerializeChanges(kTetheringBind, forwarding_map_, new_forwarding_map);
380   forwarding_map_ = new_forwarding_map;
381 }
382
383 void PortForwardingController::Connection::SerializeChanges(
384     const std::string& method,
385     const ForwardingMap& old_map,
386     const ForwardingMap& new_map) {
387   for (ForwardingMap::const_iterator new_it(new_map.begin());
388       new_it != new_map.end(); ++new_it) {
389     int port = new_it->first;
390     const std::string& location = new_it->second;
391     ForwardingMap::const_iterator old_it = old_map.find(port);
392     if (old_it != old_map.end() && old_it->second == location)
393       continue;  // The port points to the same location in both configs, skip.
394
395     SendCommand(method, port);
396   }
397 }
398
399 void PortForwardingController::Connection::SendCommand(
400     const std::string& method, int port) {
401   base::DictionaryValue params;
402   params.SetInteger(kPortAttribute, port);
403   DevToolsProtocol::Command command(++command_id_, method, &params);
404
405   if (method == kTetheringBind) {
406     pending_responses_[command.id()] =
407         base::Bind(&Connection::ProcessBindResponse,
408                    base::Unretained(this), port);
409 #if defined(DEBUG_DEVTOOLS)
410     port_status_[port] = kStatusConnecting;
411     UpdatePortStatusMap();
412 #endif  // defined(DEBUG_DEVTOOLS)
413   } else {
414     DCHECK_EQ(kTetheringUnbind, method);
415
416     PortStatusMap::iterator it = port_status_.find(port);
417     if (it != port_status_.end() && it->second == kStatusError) {
418       // The bind command failed on this port, do not attempt unbind.
419       port_status_.erase(it);
420       UpdatePortStatusMap();
421       return;
422     }
423
424     pending_responses_[command.id()] =
425         base::Bind(&Connection::ProcessUnbindResponse,
426                    base::Unretained(this), port);
427 #if defined(DEBUG_DEVTOOLS)
428     port_status_[port] = kStatusDisconnecting;
429     UpdatePortStatusMap();
430 #endif  // defined(DEBUG_DEVTOOLS)
431   }
432
433   web_socket_->SendFrameOnHandlerThread(command.Serialize());
434 }
435
436 bool PortForwardingController::Connection::ProcessResponse(
437     const std::string& message) {
438   scoped_ptr<DevToolsProtocol::Response> response(
439       DevToolsProtocol::ParseResponse(message));
440   if (!response)
441     return false;
442
443   CommandCallbackMap::iterator it = pending_responses_.find(response->id());
444   if (it == pending_responses_.end())
445     return false;
446
447   it->second.Run(response->error_code() ? kStatusError : kStatusOK);
448   pending_responses_.erase(it);
449   return true;
450 }
451
452 void PortForwardingController::Connection::ProcessBindResponse(
453     int port, PortStatus status) {
454   port_status_[port] = status;
455   UpdatePortStatusMap();
456 }
457
458 void PortForwardingController::Connection::ProcessUnbindResponse(
459     int port, PortStatus status) {
460   PortStatusMap::iterator it = port_status_.find(port);
461   if (it == port_status_.end())
462     return;
463   if (status == kStatusError)
464     it->second = status;
465   else
466     port_status_.erase(it);
467   UpdatePortStatusMap();
468 }
469
470 void PortForwardingController::Connection::UpdateSocketCount(
471     int port, int increment) {
472 #if defined(DEBUG_DEVTOOLS)
473   PortStatusMap::iterator it = port_status_.find(port);
474   if (it == port_status_.end())
475     return;
476   if (it->second < 0 || (it->second == 0 && increment < 0))
477     return;
478   it->second += increment;
479   UpdatePortStatusMap();
480 #endif  // defined(DEBUG_DEVTOOLS)
481 }
482
483 void PortForwardingController::Connection::UpdatePortStatusMap() {
484   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
485      base::Bind(&Connection::UpdatePortStatusMapOnUIThread,
486         this, port_status_));
487 }
488
489 void PortForwardingController::Connection::UpdatePortStatusMapOnUIThread(
490     const PortStatusMap& status_map) {
491   port_status_on_ui_thread_ = status_map;
492 }
493
494 const PortForwardingController::PortStatusMap&
495 PortForwardingController::Connection::GetPortStatusMap() {
496   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
497   return port_status_on_ui_thread_;
498 }
499
500 void PortForwardingController::Connection::OnSocketOpened() {
501   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
502   if (!registry_) {
503     // Socket was created after Shutdown was called. Disconnect immediately.
504     web_socket_->Disconnect();
505     return;
506   }
507   OnPrefsChange();
508   pref_change_registrar_.Add(
509       prefs::kDevToolsPortForwardingConfig,
510           base::Bind(&Connection::OnPrefsChange, base::Unretained(this)));
511 }
512
513 void PortForwardingController::Connection::OnFrameRead(
514     const std::string& message) {
515 }
516
517 void PortForwardingController::Connection::OnSocketClosed(
518     bool closed_by_device) {
519   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
520   Release();  // Balanced in the constructor.
521 }
522
523 bool PortForwardingController::Connection::ProcessIncomingMessage(
524     const std::string& message) {
525   DCHECK_EQ(base::MessageLoop::current(), adb_thread_->message_loop());
526   if (ProcessResponse(message))
527     return true;
528
529   scoped_ptr<DevToolsProtocol::Notification> notification(
530       DevToolsProtocol::ParseNotification(message));
531   if (!notification)
532     return false;
533
534   if (notification->method() != kTetheringAccepted)
535     return false;
536
537   base::DictionaryValue* params = notification->params();
538   if (!params)
539     return false;
540
541   int port;
542   std::string connection_id;
543   if (!params->GetInteger(kPortAttribute, &port) ||
544       !params->GetString(kConnectionIdAttribute, &connection_id))
545     return false;
546
547   std::map<int, std::string>::iterator it = forwarding_map_.find(port);
548   if (it == forwarding_map_.end())
549     return false;
550
551   std::string location = it->second;
552
553   SocketTunnel* tunnel = new SocketTunnel(location,
554       base::Bind(&Connection::UpdateSocketCount, this, port));
555
556   device_->OpenSocket(connection_id.c_str(),
557       base::Bind(&SocketTunnel::Start, base::Unretained(tunnel)));
558   return true;
559 }
560
561 PortForwardingController::PortForwardingController(PrefService* pref_service)
562     : adb_thread_(RefCountedAdbThread::GetInstance()),
563       pref_service_(pref_service) {
564   pref_change_registrar_.Init(pref_service);
565   base::Closure callback = base::Bind(
566       &PortForwardingController::OnPrefsChange, base::Unretained(this));
567   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled, callback);
568   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig, callback);
569 }
570
571 PortForwardingController::~PortForwardingController() {
572   ShutdownConnections();
573 }
574
575 PortForwardingController::DevicesStatus
576 PortForwardingController::UpdateDeviceList(
577     const DevToolsAdbBridge::RemoteDevices& devices) {
578   DevicesStatus status;
579   if (!ShouldCreateConnections())
580     return status;
581
582   for (DevToolsAdbBridge::RemoteDevices::const_iterator it = devices.begin();
583        it != devices.end(); ++it) {
584     scoped_refptr<DevToolsAdbBridge::RemoteDevice> device = *it;
585     if (!device->IsConnected())
586       continue;
587     Registry::iterator rit = registry_.find(device->GetSerial());
588     if (rit == registry_.end()) {
589       std::string socket = FindBestSocketForTethering(device->browsers());
590       if (!socket.empty()) {
591         new Connection(
592           &registry_, device->device(), socket, adb_thread_, pref_service_);
593       }
594     } else {
595       status[device->GetSerial()] = (*rit).second->GetPortStatusMap();
596     }
597   }
598   return status;
599 }
600
601 void PortForwardingController::OnPrefsChange() {
602   if (!ShouldCreateConnections())
603     ShutdownConnections();
604 }
605
606 bool PortForwardingController::ShouldCreateConnections() {
607   if (!pref_service_->GetBoolean(prefs::kDevToolsPortForwardingEnabled))
608     return false;
609
610   const base::DictionaryValue* dict =
611       pref_service_->GetDictionary(prefs::kDevToolsPortForwardingConfig);
612   return !base::DictionaryValue::Iterator(*dict).IsAtEnd();
613 }
614
615 void PortForwardingController::ShutdownConnections() {
616   for (Registry::iterator it = registry_.begin(); it != registry_.end(); ++it)
617     it->second->Shutdown();
618   registry_.clear();
619 }
620
621 // static
622 PortForwardingController::Factory*
623 PortForwardingController::Factory::GetInstance() {
624   return Singleton<PortForwardingController::Factory>::get();
625 }
626
627 // static
628 PortForwardingController* PortForwardingController::Factory::GetForProfile(
629     Profile* profile) {
630   return static_cast<PortForwardingController*>(GetInstance()->
631           GetServiceForBrowserContext(profile, true));
632 }
633
634 PortForwardingController::Factory::Factory()
635     : BrowserContextKeyedServiceFactory(
636           "PortForwardingController",
637           BrowserContextDependencyManager::GetInstance()) {}
638
639 PortForwardingController::Factory::~Factory() {}
640
641 KeyedService* PortForwardingController::Factory::BuildServiceInstanceFor(
642     content::BrowserContext* context) const {
643   Profile* profile = Profile::FromBrowserContext(context);
644   return new PortForwardingController(profile->GetPrefs());
645 }