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.
5 #include "remoting/host/host_status_sender.h"
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"
19 using buzz::XmlElement
;
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";
35 const char* const HostStatusSender::host_status_strings_
[] =
36 {"OFFLINE", "ONLINE"};
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
)
44 signal_strategy_(signal_strategy
),
46 directory_bot_jid_(directory_bot_jid
) {
47 DCHECK(signal_strategy_
);
48 DCHECK(key_pair_
.get());
50 signal_strategy_
->AddListener(this);
53 HostStatusSender::~HostStatusSender() {
54 signal_strategy_
->RemoveListener(this);
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
)
65 bool HostStatusSender::OnSignalStrategyIncomingStanza(
66 const XmlElement
* stanza
) {
70 void HostStatusSender::SendOfflineStatus(HostExitCodes exit_code
) {
71 SendHostStatus(OFFLINE
, exit_code
);
74 void HostStatusSender::SendOnlineStatus() {
75 SendHostStatus(ONLINE
, kSuccessExitCode
);
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
)
85 << directory_bot_jid_
;
87 iq_sender_
->SendIq(buzz::STR_SET
,
89 CreateHostStatusMessage(status
, exit_code
),
90 IqSender::ReplyCallback());
92 HOST_LOG
<< "Cannot send host status to '"
94 << " ' because the state of the SignalStrategy is "
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
));
109 if (status
== OFFLINE
) {
110 host_status
->AddAttr(
111 QName(kChromotingXmlNamespace
, kExitCodeAttr
),
112 ExitCodeToString(exit_code
));
115 host_status
->AddElement(CreateSignature(status
, exit_code
).release());
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());
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();
133 scoped_ptr
<XmlElement
> HostStatusSender::CreateSignature(
134 HostStatus status
, HostExitCodes exit_code
) {
135 scoped_ptr
<XmlElement
> signature_tag(new XmlElement(
136 QName(kChromotingXmlNamespace
, kSignatureTag
)));
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
));
142 signature_tag
->AddAttr(
143 QName(kChromotingXmlNamespace
, kSignatureTimeAttr
), time_str
);
145 // Add a time stamp to the signature to prevent replay attacks.
146 std::string message
=
147 signal_strategy_
->GetLocalJid() +
151 HostStatusToString(status
);
153 if (status
== OFFLINE
)
154 message
+= std::string(" ") + ExitCodeToString(exit_code
);
156 std::string
signature(key_pair_
->SignMessage(message
));
157 signature_tag
->AddText(signature
);
159 return signature_tag
.Pass();
162 } // namespace remoting