15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/daemon_process.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <algorithm>
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <string>
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/location.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/single_thread_task_runner.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/auto_thread_task_runner.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "remoting/base/url_request_context.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/branding.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/chromoting_messages.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "remoting/host/config_file_watcher.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/desktop_session.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/host_event_logger.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/host_status_observer.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/screen_resolution.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/protocol/transport.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is used for tagging system event logs.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kApplicationName[] = "chromoting";
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::ostream& operator<<(std::ostream& os, const ScreenResolution& resolution) {
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return os << resolution.dimensions().width() << "x"
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            << resolution.dimensions().height() << " at "
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            << resolution.dpi().x() << "x" << resolution.dpi().y() << " DPI";
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DaemonProcess::~DaemonProcess() {
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  host_event_logger_.reset();
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  config_watcher_.reset();
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DeleteAllDesktopSessions();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DaemonProcess::OnConfigUpdated(const std::string& serialized_config) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (serialized_config_ != serialized_config) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    serialized_config_ = serialized_config;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendToNetwork(
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new ChromotingDaemonNetworkMsg_Configuration(serialized_config_));
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DaemonProcess::OnConfigWatcherError() {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::AddStatusObserver(HostStatusObserver* observer) {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  status_observers_.AddObserver(observer);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::RemoveStatusObserver(HostStatusObserver* observer) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  status_observers_.RemoveObserver(observer);
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DaemonProcess::OnChannelConnected(int32 peer_pid) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "IPC: daemon <- network (" << peer_pid << ")";
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteAllDesktopSessions();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reset the last known terminal ID because no IDs have been allocated
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by the the newly started process yet.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_terminal_id_ = 0;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send the configuration to the network process.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendToNetwork(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ChromotingDaemonNetworkMsg_Configuration(serialized_config_));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DaemonProcess::OnMessageReceived(const IPC::Message& message) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = true;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP(DaemonProcess, message)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkHostMsg_ConnectTerminal,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        CreateDesktopSession)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkHostMsg_DisconnectTerminal,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        CloseDesktopSession)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_SetScreenResolution,
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        SetScreenResolution)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_AccessDenied,
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        OnAccessDenied)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientAuthenticated,
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        OnClientAuthenticated)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientConnected,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        OnClientConnected)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientDisconnected,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        OnClientDisconnected)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_ClientRouteChange,
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        OnClientRouteChange)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_HostStarted,
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        OnHostStarted)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_HostShutdown,
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        OnHostShutdown)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!handled) {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Received unexpected IPC type: " << message.type();
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid DaemonProcess::OnPermanentError(int exit_code) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DaemonProcess::CloseDesktopSession(int terminal_id) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Validate the supplied terminal ID. An attempt to use a desktop session ID
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that couldn't possibly have been allocated is considered a protocol error
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and the network process will be restarted.
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!WasTerminalIdAllocated(terminal_id)) {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Invalid terminal ID: " << terminal_id;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DesktopSessionList::iterator i;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = desktop_sessions_.begin(); i != desktop_sessions_.end(); ++i) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->id() == terminal_id) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is OK if the terminal ID wasn't found. There is a race between
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the network and daemon processes. Each frees its own recources first and
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notifies the other party if there was something to clean up.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i == desktop_sessions_.end())
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete *i;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desktop_sessions_.erase(i);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Daemon: closed desktop session " << terminal_id;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendToNetwork(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ChromotingDaemonNetworkMsg_TerminalDisconnected(terminal_id));
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DaemonProcess::DaemonProcess(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<AutoThreadTaskRunner> io_task_runner,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& stopped_callback)
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : caller_task_runner_(caller_task_runner),
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_task_runner_(io_task_runner),
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_terminal_id_(0),
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      stopped_callback_(stopped_callback),
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner->BelongsToCurrentThread());
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::CreateDesktopSession(int terminal_id,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         const ScreenResolution& resolution,
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         bool virtual_terminal) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate the supplied terminal ID. An attempt to create a desktop session
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with an ID that could possibly have been allocated already is considered
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a protocol error and the network process will be restarted.
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (WasTerminalIdAllocated(terminal_id)) {
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Invalid terminal ID: " << terminal_id;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Terminal IDs cannot be reused. Update the expected next terminal ID.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_terminal_id_ = std::max(next_terminal_id_, terminal_id + 1);
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the desktop session.
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<DesktopSession> session = DoCreateDesktopSession(
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      terminal_id, resolution, virtual_terminal);
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!session) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to create a desktop session.";
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendToNetwork(
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new ChromotingDaemonNetworkMsg_TerminalDisconnected(terminal_id));
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Daemon: opened desktop session " << terminal_id;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  desktop_sessions_.push_back(session.release());
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::SetScreenResolution(int terminal_id,
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        const ScreenResolution& resolution) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Validate the supplied terminal ID. An attempt to use a desktop session ID
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that couldn't possibly have been allocated is considered a protocol error
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and the network process will be restarted.
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!WasTerminalIdAllocated(terminal_id)) {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Invalid terminal ID: " << terminal_id;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Validate |resolution| and restart the sender if it is not valid.
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (resolution.IsEmpty()) {
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Invalid resolution specified: " << resolution;
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DesktopSessionList::iterator i;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (i = desktop_sessions_.begin(); i != desktop_sessions_.end(); ++i) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ((*i)->id() == terminal_id) {
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // It is OK if the terminal ID wasn't found. There is a race between
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the network and daemon processes. Each frees its own resources first and
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // notifies the other party if there was something to clean up.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (i == desktop_sessions_.end())
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  (*i)->SetScreenResolution(resolution);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DaemonProcess::CrashNetworkProcess(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& location) {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoCrashNetworkProcess(location);
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DeleteAllDesktopSessions();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DaemonProcess::Initialize() {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const CommandLine* command_line = CommandLine::ForCurrentProcess();
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the name of the host configuration file.
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath default_config_dir = remoting::GetConfigDir();
265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::FilePath config_path = default_config_dir.Append(
266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      kDefaultHostConfigFile);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line->HasSwitch(kHostConfigSwitchName)) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config_path = command_line->GetSwitchValuePath(kHostConfigSwitchName);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  config_watcher_.reset(new ConfigFileWatcher(
271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      caller_task_runner(), io_task_runner(), config_path));
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  config_watcher_->Watch(this);
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  host_event_logger_ =
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      HostEventLogger::Create(weak_factory_.GetWeakPtr(), kApplicationName);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch the process.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LaunchNetworkProcess();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void DaemonProcess::Stop() {
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!stopped_callback_.is_null()) {
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::Closure stopped_callback = stopped_callback_;
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    stopped_callback_.Reset();
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    stopped_callback.Run();
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DaemonProcess::WasTerminalIdAllocated(int terminal_id) {
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return terminal_id < next_terminal_id_;
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::OnAccessDenied(const std::string& jid) {
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnAccessDenied(jid));
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::OnClientAuthenticated(const std::string& jid) {
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    OnClientAuthenticated(jid));
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::OnClientConnected(const std::string& jid) {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    OnClientConnected(jid));
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::OnClientDisconnected(const std::string& jid) {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    OnClientDisconnected(jid));
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::OnClientRouteChange(const std::string& jid,
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        const std::string& channel_name,
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        const SerializedTransportRoute& route) {
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Validate |route|.
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (route.type != protocol::TransportRoute::DIRECT &&
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      route.type != protocol::TransportRoute::STUN &&
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      route.type != protocol::TransportRoute::RELAY) {
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "An invalid RouteType " << route.type << " passed.";
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (route.remote_address.size() != net::kIPv4AddressSize &&
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      route.remote_address.size() != net::kIPv6AddressSize) {
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "An invalid net::IPAddressNumber size "
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << route.remote_address.size() << " passed.";
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (route.local_address.size() != net::kIPv4AddressSize &&
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      route.local_address.size() != net::kIPv6AddressSize) {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "An invalid net::IPAddressNumber size "
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << route.local_address.size() << " passed.";
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CrashNetworkProcess(FROM_HERE);
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  protocol::TransportRoute parsed_route;
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parsed_route.type =
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<protocol::TransportRoute::RouteType>(route.type);
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parsed_route.remote_address =
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      net::IPEndPoint(route.remote_address, route.remote_port);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parsed_route.local_address =
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      net::IPEndPoint(route.local_address, route.local_port);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    OnClientRouteChange(jid, channel_name, parsed_route));
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::OnHostStarted(const std::string& xmpp_login) {
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(xmpp_login));
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DaemonProcess::OnHostShutdown() {
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(caller_task_runner()->BelongsToCurrentThread());
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DaemonProcess::DeleteAllDesktopSessions() {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!desktop_sessions_.empty()) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete desktop_sessions_.front();
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    desktop_sessions_.pop_front();
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
380