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 "chromecast/shell/browser/devtools/remote_debugging_server.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/command_line.h"
10#include "base/files/file_path.h"
11#include "base/strings/stringprintf.h"
12#include "chromecast/common/chromecast_config.h"
13#include "chromecast/common/pref_names.h"
14#include "chromecast/shell/browser/devtools/cast_dev_tools_delegate.h"
15#include "content/public/browser/browser_context.h"
16#include "content/public/browser/browser_thread.h"
17#include "content/public/browser/devtools_http_handler.h"
18#include "content/public/common/content_switches.h"
19#include "content/public/common/user_agent.h"
20#include "net/socket/tcp_server_socket.h"
21
22#if defined(OS_ANDROID)
23#include "content/public/browser/android/devtools_auth.h"
24#include "net/socket/unix_domain_server_socket_posix.h"
25#endif  // defined(OS_ANDROID)
26
27namespace chromecast {
28namespace shell {
29
30namespace {
31
32const int kDefaultRemoteDebuggingPort = 9222;
33
34#if defined(OS_ANDROID)
35class UnixDomainServerSocketFactory
36    : public content::DevToolsHttpHandler::ServerSocketFactory {
37 public:
38  explicit UnixDomainServerSocketFactory(const std::string& socket_name)
39      : content::DevToolsHttpHandler::ServerSocketFactory(socket_name, 0, 1) {}
40
41 private:
42  // content::DevToolsHttpHandler::ServerSocketFactory.
43  virtual scoped_ptr<net::ServerSocket> Create() const OVERRIDE {
44    return scoped_ptr<net::ServerSocket>(
45        new net::UnixDomainServerSocket(
46            base::Bind(&content::CanUserConnectToDevTools),
47            true /* use_abstract_namespace */));
48  }
49
50  DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory);
51};
52#else
53class TCPServerSocketFactory
54    : public content::DevToolsHttpHandler::ServerSocketFactory {
55 public:
56  TCPServerSocketFactory(const std::string& address, int port, int backlog)
57      : content::DevToolsHttpHandler::ServerSocketFactory(
58            address, port, backlog) {}
59
60 private:
61  // content::DevToolsHttpHandler::ServerSocketFactory.
62  virtual scoped_ptr<net::ServerSocket> Create() const OVERRIDE {
63    return scoped_ptr<net::ServerSocket>(
64        new net::TCPServerSocket(NULL, net::NetLog::Source()));
65  }
66
67  DISALLOW_COPY_AND_ASSIGN(TCPServerSocketFactory);
68};
69#endif
70
71scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory>
72CreateSocketFactory(int port) {
73#if defined(OS_ANDROID)
74  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
75  std::string socket_name = "content_shell_devtools_remote";
76  if (command_line->HasSwitch(switches::kRemoteDebuggingSocketName)) {
77    socket_name = command_line->GetSwitchValueASCII(
78        switches::kRemoteDebuggingSocketName);
79  }
80  return scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory>(
81      new UnixDomainServerSocketFactory(socket_name));
82#else
83  return scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory>(
84      new TCPServerSocketFactory("0.0.0.0", port, 1));
85#endif
86}
87
88}  // namespace
89
90RemoteDebuggingServer::RemoteDebuggingServer()
91    : devtools_http_handler_(NULL),
92      port_(0) {
93  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
94  pref_port_.Init(prefs::kRemoteDebuggingPort,
95                  ChromecastConfig::GetInstance()->pref_service(),
96                  base::Bind(&RemoteDebuggingServer::OnPortChanged,
97                             base::Unretained(this)));
98
99  // Starts new dev tools, clearing port number saved in config.
100  // Remote debugging in production must be triggered only by config server.
101  pref_port_.SetValue(ShouldStartImmediately() ?
102                      kDefaultRemoteDebuggingPort : 0);
103  OnPortChanged();
104}
105
106RemoteDebuggingServer::~RemoteDebuggingServer() {
107  pref_port_.SetValue(0);
108  OnPortChanged();
109}
110
111void RemoteDebuggingServer::OnPortChanged() {
112  int new_port = *pref_port_;
113  if (new_port < 0) {
114    new_port = 0;
115  }
116  VLOG(1) << "OnPortChanged called: old_port=" << port_
117          << ", new_port=" << new_port;
118
119  if (new_port == port_) {
120    VLOG(1) << "Port has not been changed. Ignore silently.";
121    return;
122  }
123
124  if (devtools_http_handler_) {
125    LOG(INFO) << "Stop old devtools: port=" << port_;
126    // Note: Stop destroys devtools_http_handler_.
127    devtools_http_handler_->Stop();
128    devtools_http_handler_ = NULL;
129  }
130
131  port_ = new_port;
132  if (port_ > 0) {
133    devtools_http_handler_ = content::DevToolsHttpHandler::Start(
134        CreateSocketFactory(port_),
135        std::string(),
136        new CastDevToolsDelegate(),
137        base::FilePath());
138    LOG(INFO) << "Devtools started: port=" << port_;
139  }
140}
141
142}  // namespace shell
143}  // namespace chromecast
144