• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HostStatusSender(const std::string & host_id,SignalStrategy * signal_strategy,scoped_refptr<RsaKeyPair> key_pair,const std::string & directory_bot_jid)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 
~HostStatusSender()53 HostStatusSender::~HostStatusSender() {
54   signal_strategy_->RemoveListener(this);
55 }
56 
OnSignalStrategyStateChange(SignalStrategy::State state)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 
OnSignalStrategyIncomingStanza(const XmlElement * stanza)65 bool HostStatusSender::OnSignalStrategyIncomingStanza(
66     const XmlElement* stanza) {
67   return false;
68 }
69 
SendOfflineStatus(HostExitCodes exit_code)70 void HostStatusSender::SendOfflineStatus(HostExitCodes exit_code) {
71   SendHostStatus(OFFLINE, exit_code);
72 }
73 
SendOnlineStatus()74 void HostStatusSender::SendOnlineStatus() {
75   SendHostStatus(ONLINE, kSuccessExitCode);
76 }
77 
SendHostStatus(HostStatus status,HostExitCodes exit_code)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 
CreateHostStatusMessage(HostStatus status,HostExitCodes exit_code)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 
CreateSignature(HostStatus status,HostExitCodes exit_code)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