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/daemon_process.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/command_line.h" 10 #include "base/file_util.h" 11 #include "base/files/file_path.h" 12 #include "base/location.h" 13 #include "base/single_thread_task_runner.h" 14 #include "net/base/net_util.h" 15 #include "remoting/base/auto_thread_task_runner.h" 16 #include "remoting/host/branding.h" 17 #include "remoting/host/chromoting_messages.h" 18 #include "remoting/host/desktop_session.h" 19 #include "remoting/host/host_event_logger.h" 20 #include "remoting/host/host_status_observer.h" 21 #include "remoting/host/screen_resolution.h" 22 #include "remoting/protocol/transport.h" 23 24 namespace remoting { 25 26 namespace { 27 28 // This is used for tagging system event logs. 29 const char kApplicationName[] = "chromoting"; 30 31 std::ostream& operator<<(std::ostream& os, const ScreenResolution& resolution) { 32 return os << resolution.dimensions().width() << "x" 33 << resolution.dimensions().height() << " at " 34 << resolution.dpi().x() << "x" << resolution.dpi().y() << " DPI"; 35 } 36 37 } // namespace 38 39 DaemonProcess::~DaemonProcess() { 40 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 41 42 host_event_logger_.reset(); 43 weak_factory_.InvalidateWeakPtrs(); 44 45 config_watcher_.reset(); 46 DeleteAllDesktopSessions(); 47 } 48 49 void DaemonProcess::OnConfigUpdated(const std::string& serialized_config) { 50 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 51 52 if (serialized_config_ != serialized_config) { 53 serialized_config_ = serialized_config; 54 SendToNetwork( 55 new ChromotingDaemonNetworkMsg_Configuration(serialized_config_)); 56 } 57 } 58 59 void DaemonProcess::OnConfigWatcherError() { 60 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 61 62 Stop(); 63 } 64 65 void DaemonProcess::AddStatusObserver(HostStatusObserver* observer) { 66 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 67 68 status_observers_.AddObserver(observer); 69 } 70 71 void DaemonProcess::RemoveStatusObserver(HostStatusObserver* observer) { 72 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 73 74 status_observers_.RemoveObserver(observer); 75 } 76 77 void DaemonProcess::OnChannelConnected(int32 peer_pid) { 78 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 79 80 VLOG(1) << "IPC: daemon <- network (" << peer_pid << ")"; 81 82 DeleteAllDesktopSessions(); 83 84 // Reset the last known terminal ID because no IDs have been allocated 85 // by the the newly started process yet. 86 next_terminal_id_ = 0; 87 88 // Send the configuration to the network process. 89 SendToNetwork( 90 new ChromotingDaemonNetworkMsg_Configuration(serialized_config_)); 91 } 92 93 bool DaemonProcess::OnMessageReceived(const IPC::Message& message) { 94 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 95 96 bool handled = true; 97 IPC_BEGIN_MESSAGE_MAP(DaemonProcess, message) 98 IPC_MESSAGE_HANDLER(ChromotingNetworkHostMsg_ConnectTerminal, 99 CreateDesktopSession) 100 IPC_MESSAGE_HANDLER(ChromotingNetworkHostMsg_DisconnectTerminal, 101 CloseDesktopSession) 102 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_SetScreenResolution, 103 SetScreenResolution) 104 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_AccessDenied, 105 OnAccessDenied) 106 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientAuthenticated, 107 OnClientAuthenticated) 108 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientConnected, 109 OnClientConnected) 110 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientDisconnected, 111 OnClientDisconnected) 112 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientRouteChange, 113 OnClientRouteChange) 114 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_HostStarted, 115 OnHostStarted) 116 IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_HostShutdown, 117 OnHostShutdown) 118 IPC_MESSAGE_UNHANDLED(handled = false) 119 IPC_END_MESSAGE_MAP() 120 121 if (!handled) { 122 LOG(ERROR) << "Received unexpected IPC type: " << message.type(); 123 CrashNetworkProcess(FROM_HERE); 124 } 125 126 return handled; 127 } 128 129 void DaemonProcess::OnPermanentError(int exit_code) { 130 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 131 Stop(); 132 } 133 134 void DaemonProcess::CloseDesktopSession(int terminal_id) { 135 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 136 137 // Validate the supplied terminal ID. An attempt to use a desktop session ID 138 // that couldn't possibly have been allocated is considered a protocol error 139 // and the network process will be restarted. 140 if (!WasTerminalIdAllocated(terminal_id)) { 141 LOG(ERROR) << "Invalid terminal ID: " << terminal_id; 142 CrashNetworkProcess(FROM_HERE); 143 return; 144 } 145 146 DesktopSessionList::iterator i; 147 for (i = desktop_sessions_.begin(); i != desktop_sessions_.end(); ++i) { 148 if ((*i)->id() == terminal_id) { 149 break; 150 } 151 } 152 153 // It is OK if the terminal ID wasn't found. There is a race between 154 // the network and daemon processes. Each frees its own recources first and 155 // notifies the other party if there was something to clean up. 156 if (i == desktop_sessions_.end()) 157 return; 158 159 delete *i; 160 desktop_sessions_.erase(i); 161 162 VLOG(1) << "Daemon: closed desktop session " << terminal_id; 163 SendToNetwork( 164 new ChromotingDaemonNetworkMsg_TerminalDisconnected(terminal_id)); 165 } 166 167 DaemonProcess::DaemonProcess( 168 scoped_refptr<AutoThreadTaskRunner> caller_task_runner, 169 scoped_refptr<AutoThreadTaskRunner> io_task_runner, 170 const base::Closure& stopped_callback) 171 : caller_task_runner_(caller_task_runner), 172 io_task_runner_(io_task_runner), 173 next_terminal_id_(0), 174 stopped_callback_(stopped_callback), 175 weak_factory_(this) { 176 DCHECK(caller_task_runner->BelongsToCurrentThread()); 177 } 178 179 void DaemonProcess::CreateDesktopSession(int terminal_id, 180 const ScreenResolution& resolution, 181 bool virtual_terminal) { 182 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 183 184 // Validate the supplied terminal ID. An attempt to create a desktop session 185 // with an ID that could possibly have been allocated already is considered 186 // a protocol error and the network process will be restarted. 187 if (WasTerminalIdAllocated(terminal_id)) { 188 LOG(ERROR) << "Invalid terminal ID: " << terminal_id; 189 CrashNetworkProcess(FROM_HERE); 190 return; 191 } 192 193 // Terminal IDs cannot be reused. Update the expected next terminal ID. 194 next_terminal_id_ = std::max(next_terminal_id_, terminal_id + 1); 195 196 // Create the desktop session. 197 scoped_ptr<DesktopSession> session = DoCreateDesktopSession( 198 terminal_id, resolution, virtual_terminal); 199 if (!session) { 200 LOG(ERROR) << "Failed to create a desktop session."; 201 SendToNetwork( 202 new ChromotingDaemonNetworkMsg_TerminalDisconnected(terminal_id)); 203 return; 204 } 205 206 VLOG(1) << "Daemon: opened desktop session " << terminal_id; 207 desktop_sessions_.push_back(session.release()); 208 } 209 210 void DaemonProcess::SetScreenResolution(int terminal_id, 211 const ScreenResolution& resolution) { 212 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 213 214 // Validate the supplied terminal ID. An attempt to use a desktop session ID 215 // that couldn't possibly have been allocated is considered a protocol error 216 // and the network process will be restarted. 217 if (!WasTerminalIdAllocated(terminal_id)) { 218 LOG(ERROR) << "Invalid terminal ID: " << terminal_id; 219 CrashNetworkProcess(FROM_HERE); 220 return; 221 } 222 223 // Validate |resolution| and restart the sender if it is not valid. 224 if (resolution.IsEmpty()) { 225 LOG(ERROR) << "Invalid resolution specified: " << resolution; 226 CrashNetworkProcess(FROM_HERE); 227 return; 228 } 229 230 DesktopSessionList::iterator i; 231 for (i = desktop_sessions_.begin(); i != desktop_sessions_.end(); ++i) { 232 if ((*i)->id() == terminal_id) { 233 break; 234 } 235 } 236 237 // It is OK if the terminal ID wasn't found. There is a race between 238 // the network and daemon processes. Each frees its own resources first and 239 // notifies the other party if there was something to clean up. 240 if (i == desktop_sessions_.end()) 241 return; 242 243 (*i)->SetScreenResolution(resolution); 244 } 245 246 void DaemonProcess::CrashNetworkProcess( 247 const tracked_objects::Location& location) { 248 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 249 250 DoCrashNetworkProcess(location); 251 DeleteAllDesktopSessions(); 252 } 253 254 void DaemonProcess::Initialize() { 255 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 256 257 // Get the name of the host configuration file. 258 base::FilePath default_config_dir = remoting::GetConfigDir(); 259 base::FilePath config_path = default_config_dir.Append(kDefaultHostConfigFile); 260 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 261 if (command_line->HasSwitch(kHostConfigSwitchName)) { 262 config_path = command_line->GetSwitchValuePath(kHostConfigSwitchName); 263 } 264 265 // Start watching the host configuration file. 266 config_watcher_.reset(new ConfigFileWatcher(caller_task_runner(), 267 io_task_runner(), 268 this)); 269 config_watcher_->Watch(config_path); 270 271 host_event_logger_ = 272 HostEventLogger::Create(weak_factory_.GetWeakPtr(), kApplicationName); 273 274 // Launch the process. 275 LaunchNetworkProcess(); 276 } 277 278 void DaemonProcess::Stop() { 279 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 280 281 if (!stopped_callback_.is_null()) { 282 base::Closure stopped_callback = stopped_callback_; 283 stopped_callback_.Reset(); 284 stopped_callback.Run(); 285 } 286 } 287 288 bool DaemonProcess::WasTerminalIdAllocated(int terminal_id) { 289 return terminal_id < next_terminal_id_; 290 } 291 292 void DaemonProcess::OnAccessDenied(const std::string& jid) { 293 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 294 295 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnAccessDenied(jid)); 296 } 297 298 void DaemonProcess::OnClientAuthenticated(const std::string& jid) { 299 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 300 301 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 302 OnClientAuthenticated(jid)); 303 } 304 305 void DaemonProcess::OnClientConnected(const std::string& jid) { 306 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 307 308 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 309 OnClientConnected(jid)); 310 } 311 312 void DaemonProcess::OnClientDisconnected(const std::string& jid) { 313 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 314 315 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 316 OnClientDisconnected(jid)); 317 } 318 319 void DaemonProcess::OnClientRouteChange(const std::string& jid, 320 const std::string& channel_name, 321 const SerializedTransportRoute& route) { 322 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 323 324 // Validate |route|. 325 if (route.type != protocol::TransportRoute::DIRECT && 326 route.type != protocol::TransportRoute::STUN && 327 route.type != protocol::TransportRoute::RELAY) { 328 LOG(ERROR) << "An invalid RouteType " << route.type << " passed."; 329 CrashNetworkProcess(FROM_HERE); 330 return; 331 } 332 if (route.remote_address.size() != net::kIPv4AddressSize && 333 route.remote_address.size() != net::kIPv6AddressSize) { 334 LOG(ERROR) << "An invalid net::IPAddressNumber size " 335 << route.remote_address.size() << " passed."; 336 CrashNetworkProcess(FROM_HERE); 337 return; 338 } 339 if (route.local_address.size() != net::kIPv4AddressSize && 340 route.local_address.size() != net::kIPv6AddressSize) { 341 LOG(ERROR) << "An invalid net::IPAddressNumber size " 342 << route.local_address.size() << " passed."; 343 CrashNetworkProcess(FROM_HERE); 344 return; 345 } 346 347 protocol::TransportRoute parsed_route; 348 parsed_route.type = 349 static_cast<protocol::TransportRoute::RouteType>(route.type); 350 parsed_route.remote_address = 351 net::IPEndPoint(route.remote_address, route.remote_port); 352 parsed_route.local_address = 353 net::IPEndPoint(route.local_address, route.local_port); 354 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, 355 OnClientRouteChange(jid, channel_name, parsed_route)); 356 } 357 358 void DaemonProcess::OnHostStarted(const std::string& xmpp_login) { 359 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 360 361 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(xmpp_login)); 362 } 363 364 void DaemonProcess::OnHostShutdown() { 365 DCHECK(caller_task_runner()->BelongsToCurrentThread()); 366 367 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown()); 368 } 369 370 void DaemonProcess::DeleteAllDesktopSessions() { 371 while (!desktop_sessions_.empty()) { 372 delete desktop_sessions_.front(); 373 desktop_sessions_.pop_front(); 374 } 375 } 376 377 } // namespace remoting 378