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