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 24 namespace remoting { 25 26 IpcDesktopEnvironment::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 45 IpcDesktopEnvironment::~IpcDesktopEnvironment() { 46 } 47 48 scoped_ptr<AudioCapturer> IpcDesktopEnvironment::CreateAudioCapturer() { 49 return desktop_session_proxy_->CreateAudioCapturer(); 50 } 51 52 scoped_ptr<InputInjector> IpcDesktopEnvironment::CreateInputInjector() { 53 return desktop_session_proxy_->CreateInputInjector(); 54 } 55 56 scoped_ptr<ScreenControls> IpcDesktopEnvironment::CreateScreenControls() { 57 return desktop_session_proxy_->CreateScreenControls(); 58 } 59 60 scoped_ptr<webrtc::ScreenCapturer> 61 IpcDesktopEnvironment::CreateVideoCapturer() { 62 return desktop_session_proxy_->CreateVideoCapturer(); 63 } 64 65 std::string IpcDesktopEnvironment::GetCapabilities() const { 66 return desktop_session_proxy_->GetCapabilities(); 67 } 68 69 void IpcDesktopEnvironment::SetCapabilities(const std::string& capabilities) { 70 return desktop_session_proxy_->SetCapabilities(capabilities); 71 } 72 73 scoped_ptr<GnubbyAuthHandler> IpcDesktopEnvironment::CreateGnubbyAuthHandler( 74 protocol::ClientStub* client_stub) { 75 return scoped_ptr<GnubbyAuthHandler>(); 76 } 77 78 IpcDesktopEnvironmentFactory::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 94 IpcDesktopEnvironmentFactory::~IpcDesktopEnvironmentFactory() { 95 } 96 97 scoped_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 111 void IpcDesktopEnvironmentFactory::SetEnableCurtaining(bool enable) { 112 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 113 114 curtain_enabled_ = enable; 115 } 116 117 bool IpcDesktopEnvironmentFactory::SupportsAudioCapture() const { 118 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 119 120 return AudioCapturer::IsSupported(); 121 } 122 123 void 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 140 void 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 159 void 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 176 void 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 201 void 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