Home | History | Annotate | Download | only in host
      1 // Copyright 2013 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/host_status_sender.h"
      6 
      7 #include "base/strings/string_number_conversions.h"
      8 #include "base/strings/stringize_macros.h"
      9 #include "base/time/time.h"
     10 #include "remoting/base/constants.h"
     11 #include "remoting/base/logging.h"
     12 #include "remoting/host/server_log_entry_host.h"
     13 #include "remoting/jingle_glue/iq_sender.h"
     14 #include "remoting/jingle_glue/server_log_entry.h"
     15 #include "remoting/jingle_glue/signal_strategy.h"
     16 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
     17 #include "third_party/libjingle/source/talk/xmpp/constants.h"
     18 
     19 using buzz::QName;
     20 using buzz::XmlElement;
     21 
     22 namespace remoting {
     23 
     24 namespace {
     25 
     26 const char kHostStatusTag[] = "host-status";
     27 const char kHostIdAttr[] = "hostid";
     28 const char kExitCodeAttr[] = "exit-code";
     29 const char kHostVersionTag[] = "host-version";
     30 const char kSignatureTag[] = "signature";
     31 const char kStatusAttr[] = "status";
     32 const char kSignatureTimeAttr[] = "time";
     33 
     34 }  // namespace
     35 
     36 const char* const HostStatusSender::host_status_strings_[] =
     37 {"OFFLINE", "ONLINE"};
     38 
     39 HostStatusSender::HostStatusSender(
     40     const std::string& host_id,
     41     SignalStrategy* signal_strategy,
     42     scoped_refptr<RsaKeyPair> key_pair,
     43     const std::string& directory_bot_jid)
     44     : host_id_(host_id),
     45       signal_strategy_(signal_strategy),
     46       key_pair_(key_pair),
     47       directory_bot_jid_(directory_bot_jid) {
     48   DCHECK(signal_strategy_);
     49   DCHECK(key_pair_.get());
     50 
     51   signal_strategy_->AddListener(this);
     52 }
     53 
     54 HostStatusSender::~HostStatusSender() {
     55   signal_strategy_->RemoveListener(this);
     56 }
     57 
     58 void HostStatusSender::OnSignalStrategyStateChange(
     59     SignalStrategy::State state) {
     60   if (state == SignalStrategy::CONNECTED)
     61     iq_sender_.reset(new IqSender(signal_strategy_));
     62   else if (state == SignalStrategy::DISCONNECTED)
     63     iq_sender_.reset();
     64 }
     65 
     66 bool HostStatusSender::OnSignalStrategyIncomingStanza(
     67     const XmlElement* stanza) {
     68   return false;
     69 }
     70 
     71 void HostStatusSender::SendOfflineStatus(HostExitCodes exit_code) {
     72   SendHostStatus(OFFLINE, exit_code);
     73 }
     74 
     75 void HostStatusSender::SendOnlineStatus() {
     76   SendHostStatus(ONLINE, kSuccessExitCode);
     77 }
     78 
     79 void HostStatusSender::SendHostStatus(HostStatus status,
     80                                       HostExitCodes exit_code) {
     81   SignalStrategy::State state = signal_strategy_->GetState();
     82   if (state == SignalStrategy::CONNECTED) {
     83     HOST_LOG << "Sending host status '"
     84               << HostStatusToString(status)
     85               << "' to "
     86               << directory_bot_jid_;
     87 
     88     iq_sender_->SendIq(buzz::STR_SET,
     89                        directory_bot_jid_,
     90                        CreateHostStatusMessage(status, exit_code),
     91                        IqSender::ReplyCallback());
     92   } else {
     93     HOST_LOG << "Cannot send host status to '"
     94               << directory_bot_jid_
     95               << " ' because the state of the SignalStrategy is "
     96               << state;
     97   }
     98 }
     99 
    100 scoped_ptr<XmlElement> HostStatusSender::CreateHostStatusMessage(
    101     HostStatus status, HostExitCodes exit_code) {
    102   // Create host status stanza.
    103   scoped_ptr<XmlElement> host_status(new XmlElement(
    104       QName(kChromotingXmlNamespace, kHostStatusTag)));
    105   host_status->AddAttr(
    106       QName(kChromotingXmlNamespace, kHostIdAttr), host_id_);
    107   host_status->AddAttr(
    108       QName(kChromotingXmlNamespace, kStatusAttr), HostStatusToString(status));
    109 
    110   if (status == OFFLINE) {
    111     host_status->AddAttr(
    112         QName(kChromotingXmlNamespace, kExitCodeAttr),
    113         ExitCodeToString(exit_code));
    114   }
    115 
    116   host_status->AddElement(CreateSignature(status, exit_code).release());
    117 
    118   // Append host version.
    119   scoped_ptr<XmlElement> version_tag(new XmlElement(
    120       QName(kChromotingXmlNamespace, kHostVersionTag)));
    121   version_tag->AddText(STRINGIZE(VERSION));
    122   host_status->AddElement(version_tag.release());
    123 
    124   // Append log message (which isn't signed).
    125   scoped_ptr<XmlElement> log(ServerLogEntry::MakeStanza());
    126   scoped_ptr<ServerLogEntry> log_entry(
    127       MakeLogEntryForHostStatus(status, exit_code));
    128   AddHostFieldsToLogEntry(log_entry.get());
    129   log->AddElement(log_entry->ToStanza().release());
    130   host_status->AddElement(log.release());
    131   return host_status.Pass();
    132 }
    133 
    134 scoped_ptr<XmlElement> HostStatusSender::CreateSignature(
    135     HostStatus status, HostExitCodes exit_code) {
    136   scoped_ptr<XmlElement> signature_tag(new XmlElement(
    137       QName(kChromotingXmlNamespace, kSignatureTag)));
    138 
    139   // Number of seconds since epoch (Jan 1, 1970).
    140   int64 time = static_cast<int64>(base::Time::Now().ToDoubleT());
    141   std::string time_str(base::Int64ToString(time));
    142 
    143   signature_tag->AddAttr(
    144       QName(kChromotingXmlNamespace, kSignatureTimeAttr), time_str);
    145 
    146   // Add a time stamp to the signature to prevent replay attacks.
    147   std::string message =
    148       signal_strategy_->GetLocalJid() +
    149       " " +
    150       time_str +
    151       " " +
    152       HostStatusToString(status);
    153 
    154   if (status == OFFLINE)
    155     message += std::string(" ") + ExitCodeToString(exit_code);
    156 
    157   std::string signature(key_pair_->SignMessage(message));
    158   signature_tag->AddText(signature);
    159 
    160   return signature_tag.Pass();
    161 }
    162 
    163 }  // namespace remoting
    164