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