Revert 207377 "Disable TabCaptureApiTest.EndToEnd for Linux (non..."
[chromium-blink-merge.git] / remoting / host / daemon_process.cc
blobf5f0a6da2255f9b21fb18b2bf320ed5f0cfa9d02
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.
5 #include "remoting/host/daemon_process.h"
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"
24 namespace remoting {
26 namespace {
28 // This is used for tagging system event logs.
29 const char kApplicationName[] = "chromoting";
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";
37 } // namespace
39 DaemonProcess::~DaemonProcess() {
40 DCHECK(caller_task_runner()->BelongsToCurrentThread());
42 host_event_logger_.reset();
43 weak_factory_.InvalidateWeakPtrs();
45 config_watcher_.reset();
46 DeleteAllDesktopSessions();
49 void DaemonProcess::OnConfigUpdated(const std::string& serialized_config) {
50 DCHECK(caller_task_runner()->BelongsToCurrentThread());
52 if (serialized_config_ != serialized_config) {
53 serialized_config_ = serialized_config;
54 SendToNetwork(
55 new ChromotingDaemonNetworkMsg_Configuration(serialized_config_));
59 void DaemonProcess::OnConfigWatcherError() {
60 DCHECK(caller_task_runner()->BelongsToCurrentThread());
62 Stop();
65 void DaemonProcess::AddStatusObserver(HostStatusObserver* observer) {
66 DCHECK(caller_task_runner()->BelongsToCurrentThread());
68 status_observers_.AddObserver(observer);
71 void DaemonProcess::RemoveStatusObserver(HostStatusObserver* observer) {
72 DCHECK(caller_task_runner()->BelongsToCurrentThread());
74 status_observers_.RemoveObserver(observer);
77 void DaemonProcess::OnChannelConnected(int32 peer_pid) {
78 DCHECK(caller_task_runner()->BelongsToCurrentThread());
80 VLOG(1) << "IPC: daemon <- network (" << peer_pid << ")";
82 DeleteAllDesktopSessions();
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;
88 // Send the configuration to the network process.
89 SendToNetwork(
90 new ChromotingDaemonNetworkMsg_Configuration(serialized_config_));
93 bool DaemonProcess::OnMessageReceived(const IPC::Message& message) {
94 DCHECK(caller_task_runner()->BelongsToCurrentThread());
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()
121 if (!handled) {
122 LOG(ERROR) << "Received unexpected IPC type: " << message.type();
123 CrashNetworkProcess(FROM_HERE);
126 return handled;
129 void DaemonProcess::OnPermanentError(int exit_code) {
130 DCHECK(caller_task_runner()->BelongsToCurrentThread());
131 Stop();
134 void DaemonProcess::CloseDesktopSession(int terminal_id) {
135 DCHECK(caller_task_runner()->BelongsToCurrentThread());
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;
146 DesktopSessionList::iterator i;
147 for (i = desktop_sessions_.begin(); i != desktop_sessions_.end(); ++i) {
148 if ((*i)->id() == terminal_id) {
149 break;
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;
159 delete *i;
160 desktop_sessions_.erase(i);
162 VLOG(1) << "Daemon: closed desktop session " << terminal_id;
163 SendToNetwork(
164 new ChromotingDaemonNetworkMsg_TerminalDisconnected(terminal_id));
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());
179 void DaemonProcess::CreateDesktopSession(int terminal_id,
180 const ScreenResolution& resolution,
181 bool virtual_terminal) {
182 DCHECK(caller_task_runner()->BelongsToCurrentThread());
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;
193 // Terminal IDs cannot be reused. Update the expected next terminal ID.
194 next_terminal_id_ = std::max(next_terminal_id_, terminal_id + 1);
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;
206 VLOG(1) << "Daemon: opened desktop session " << terminal_id;
207 desktop_sessions_.push_back(session.release());
210 void DaemonProcess::SetScreenResolution(int terminal_id,
211 const ScreenResolution& resolution) {
212 DCHECK(caller_task_runner()->BelongsToCurrentThread());
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;
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;
230 DesktopSessionList::iterator i;
231 for (i = desktop_sessions_.begin(); i != desktop_sessions_.end(); ++i) {
232 if ((*i)->id() == terminal_id) {
233 break;
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;
243 (*i)->SetScreenResolution(resolution);
246 void DaemonProcess::CrashNetworkProcess(
247 const tracked_objects::Location& location) {
248 DCHECK(caller_task_runner()->BelongsToCurrentThread());
250 DoCrashNetworkProcess(location);
251 DeleteAllDesktopSessions();
254 void DaemonProcess::Initialize() {
255 DCHECK(caller_task_runner()->BelongsToCurrentThread());
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);
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);
271 host_event_logger_ =
272 HostEventLogger::Create(weak_factory_.GetWeakPtr(), kApplicationName);
274 // Launch the process.
275 LaunchNetworkProcess();
278 void DaemonProcess::Stop() {
279 DCHECK(caller_task_runner()->BelongsToCurrentThread());
281 if (!stopped_callback_.is_null()) {
282 base::Closure stopped_callback = stopped_callback_;
283 stopped_callback_.Reset();
284 stopped_callback.Run();
288 bool DaemonProcess::WasTerminalIdAllocated(int terminal_id) {
289 return terminal_id < next_terminal_id_;
292 void DaemonProcess::OnAccessDenied(const std::string& jid) {
293 DCHECK(caller_task_runner()->BelongsToCurrentThread());
295 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnAccessDenied(jid));
298 void DaemonProcess::OnClientAuthenticated(const std::string& jid) {
299 DCHECK(caller_task_runner()->BelongsToCurrentThread());
301 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
302 OnClientAuthenticated(jid));
305 void DaemonProcess::OnClientConnected(const std::string& jid) {
306 DCHECK(caller_task_runner()->BelongsToCurrentThread());
308 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
309 OnClientConnected(jid));
312 void DaemonProcess::OnClientDisconnected(const std::string& jid) {
313 DCHECK(caller_task_runner()->BelongsToCurrentThread());
315 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
316 OnClientDisconnected(jid));
319 void DaemonProcess::OnClientRouteChange(const std::string& jid,
320 const std::string& channel_name,
321 const SerializedTransportRoute& route) {
322 DCHECK(caller_task_runner()->BelongsToCurrentThread());
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;
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;
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;
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));
358 void DaemonProcess::OnHostStarted(const std::string& xmpp_login) {
359 DCHECK(caller_task_runner()->BelongsToCurrentThread());
361 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(xmpp_login));
364 void DaemonProcess::OnHostShutdown() {
365 DCHECK(caller_task_runner()->BelongsToCurrentThread());
367 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
370 void DaemonProcess::DeleteAllDesktopSessions() {
371 while (!desktop_sessions_.empty()) {
372 delete desktop_sessions_.front();
373 desktop_sessions_.pop_front();
377 } // namespace remoting