1// Copyright (c) 2012 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 "remoting/host/ipc_desktop_environment.h"
6
7#include <utility>
8
9#include "base/compiler_specific.h"
10#include "base/logging.h"
11#include "base/process/process_handle.h"
12#include "base/single_thread_task_runner.h"
13#include "ipc/ipc_sender.h"
14#include "remoting/host/audio_capturer.h"
15#include "remoting/host/chromoting_messages.h"
16#include "remoting/host/client_session_control.h"
17#include "remoting/host/desktop_session.h"
18#include "remoting/host/desktop_session_proxy.h"
19#include "remoting/host/gnubby_auth_handler.h"
20#include "remoting/host/input_injector.h"
21#include "remoting/host/screen_controls.h"
22#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
23
24namespace remoting {
25
26IpcDesktopEnvironment::IpcDesktopEnvironment(
27    scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
28    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
29    scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner,
30    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
31    base::WeakPtr<ClientSessionControl> client_session_control,
32    base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
33    bool virtual_terminal) {
34  DCHECK(caller_task_runner->BelongsToCurrentThread());
35
36  desktop_session_proxy_ = new DesktopSessionProxy(audio_task_runner,
37                                                   caller_task_runner,
38                                                   io_task_runner,
39                                                   capture_task_runner,
40                                                   client_session_control,
41                                                   desktop_session_connector,
42                                                   virtual_terminal);
43}
44
45IpcDesktopEnvironment::~IpcDesktopEnvironment() {
46}
47
48scoped_ptr<AudioCapturer> IpcDesktopEnvironment::CreateAudioCapturer() {
49  return desktop_session_proxy_->CreateAudioCapturer();
50}
51
52scoped_ptr<InputInjector> IpcDesktopEnvironment::CreateInputInjector() {
53  return desktop_session_proxy_->CreateInputInjector();
54}
55
56scoped_ptr<ScreenControls> IpcDesktopEnvironment::CreateScreenControls() {
57  return desktop_session_proxy_->CreateScreenControls();
58}
59
60scoped_ptr<webrtc::ScreenCapturer>
61IpcDesktopEnvironment::CreateVideoCapturer() {
62  return desktop_session_proxy_->CreateVideoCapturer();
63}
64
65std::string IpcDesktopEnvironment::GetCapabilities() const {
66  return desktop_session_proxy_->GetCapabilities();
67}
68
69void IpcDesktopEnvironment::SetCapabilities(const std::string& capabilities) {
70  return desktop_session_proxy_->SetCapabilities(capabilities);
71}
72
73scoped_ptr<GnubbyAuthHandler> IpcDesktopEnvironment::CreateGnubbyAuthHandler(
74    protocol::ClientStub* client_stub) {
75  return scoped_ptr<GnubbyAuthHandler>();
76}
77
78IpcDesktopEnvironmentFactory::IpcDesktopEnvironmentFactory(
79    scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
80    scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
81    scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner,
82    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
83    IPC::Sender* daemon_channel)
84    : audio_task_runner_(audio_task_runner),
85      caller_task_runner_(caller_task_runner),
86      capture_task_runner_(capture_task_runner),
87      io_task_runner_(io_task_runner),
88      curtain_enabled_(false),
89      daemon_channel_(daemon_channel),
90      connector_factory_(this),
91      next_id_(0) {
92}
93
94IpcDesktopEnvironmentFactory::~IpcDesktopEnvironmentFactory() {
95}
96
97scoped_ptr<DesktopEnvironment> IpcDesktopEnvironmentFactory::Create(
98    base::WeakPtr<ClientSessionControl> client_session_control) {
99  DCHECK(caller_task_runner_->BelongsToCurrentThread());
100
101  return scoped_ptr<DesktopEnvironment>(
102      new IpcDesktopEnvironment(audio_task_runner_,
103                                caller_task_runner_,
104                                capture_task_runner_,
105                                io_task_runner_,
106                                client_session_control,
107                                connector_factory_.GetWeakPtr(),
108                                curtain_enabled_));
109}
110
111void IpcDesktopEnvironmentFactory::SetEnableCurtaining(bool enable) {
112  DCHECK(caller_task_runner_->BelongsToCurrentThread());
113
114  curtain_enabled_ = enable;
115}
116
117bool IpcDesktopEnvironmentFactory::SupportsAudioCapture() const {
118  DCHECK(caller_task_runner_->BelongsToCurrentThread());
119
120  return AudioCapturer::IsSupported();
121}
122
123void IpcDesktopEnvironmentFactory::ConnectTerminal(
124    DesktopSessionProxy* desktop_session_proxy,
125    const ScreenResolution& resolution,
126    bool virtual_terminal) {
127  DCHECK(caller_task_runner_->BelongsToCurrentThread());
128
129  int id = next_id_++;
130  bool inserted = active_connections_.insert(
131      std::make_pair(id, desktop_session_proxy)).second;
132  CHECK(inserted);
133
134  VLOG(1) << "Network: registered desktop environment " << id;
135
136  daemon_channel_->Send(new ChromotingNetworkHostMsg_ConnectTerminal(
137      id, resolution, virtual_terminal));
138}
139
140void IpcDesktopEnvironmentFactory::DisconnectTerminal(
141    DesktopSessionProxy* desktop_session_proxy) {
142  DCHECK(caller_task_runner_->BelongsToCurrentThread());
143
144  ActiveConnectionsList::iterator i;
145  for (i = active_connections_.begin(); i != active_connections_.end(); ++i) {
146    if (i->second == desktop_session_proxy)
147      break;
148  }
149
150  if (i != active_connections_.end()) {
151    int id = i->first;
152    active_connections_.erase(i);
153
154    VLOG(1) << "Network: unregistered desktop environment " << id;
155    daemon_channel_->Send(new ChromotingNetworkHostMsg_DisconnectTerminal(id));
156  }
157}
158
159void IpcDesktopEnvironmentFactory::SetScreenResolution(
160    DesktopSessionProxy* desktop_session_proxy,
161    const ScreenResolution& resolution) {
162  DCHECK(caller_task_runner_->BelongsToCurrentThread());
163
164  ActiveConnectionsList::iterator i;
165  for (i = active_connections_.begin(); i != active_connections_.end(); ++i) {
166    if (i->second == desktop_session_proxy)
167      break;
168  }
169
170  if (i != active_connections_.end()) {
171    daemon_channel_->Send(new ChromotingNetworkDaemonMsg_SetScreenResolution(
172        i->first, resolution));
173  }
174}
175
176void IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached(
177    int terminal_id,
178    base::ProcessHandle desktop_process,
179    IPC::PlatformFileForTransit desktop_pipe) {
180  if (!caller_task_runner_->BelongsToCurrentThread()) {
181    caller_task_runner_->PostTask(FROM_HERE, base::Bind(
182        &IpcDesktopEnvironmentFactory::OnDesktopSessionAgentAttached,
183        base::Unretained(this), terminal_id, desktop_process, desktop_pipe));
184    return;
185  }
186
187  ActiveConnectionsList::iterator i = active_connections_.find(terminal_id);
188  if (i != active_connections_.end()) {
189    i->second->DetachFromDesktop();
190    i->second->AttachToDesktop(desktop_process, desktop_pipe);
191  } else {
192    base::CloseProcessHandle(desktop_process);
193
194#if defined(OS_POSIX)
195    DCHECK(desktop_pipe.auto_close);
196    base::File pipe_closer(IPC::PlatformFileForTransitToFile(desktop_pipe));
197#endif  // defined(OS_POSIX)
198  }
199}
200
201void IpcDesktopEnvironmentFactory::OnTerminalDisconnected(int terminal_id) {
202  if (!caller_task_runner_->BelongsToCurrentThread()) {
203    caller_task_runner_->PostTask(FROM_HERE, base::Bind(
204        &IpcDesktopEnvironmentFactory::OnTerminalDisconnected,
205        base::Unretained(this), terminal_id));
206    return;
207  }
208
209  ActiveConnectionsList::iterator i = active_connections_.find(terminal_id);
210  if (i != active_connections_.end()) {
211    DesktopSessionProxy* desktop_session_proxy = i->second;
212    active_connections_.erase(i);
213
214    // Disconnect the client session.
215    desktop_session_proxy->DisconnectSession();
216  }
217}
218
219}  // namespace remoting
220