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