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_host.h"
13 #include "remoting/signaling/iq_sender.h"
14 #include "remoting/signaling/server_log_entry.h"
15 #include "remoting/signaling/signal_strategy.h"
16 #include "third_party/libjingle/source/talk/xmpp/constants.h"
17 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
20 using buzz::XmlElement
;
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";
36 const char* const HostStatusSender::host_status_strings_
[] =
37 {"OFFLINE", "ONLINE"};
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
)
45 signal_strategy_(signal_strategy
),
47 directory_bot_jid_(directory_bot_jid
) {
48 DCHECK(signal_strategy_
);
49 DCHECK(key_pair_
.get());
51 signal_strategy_
->AddListener(this);
54 HostStatusSender::~HostStatusSender() {
55 signal_strategy_
->RemoveListener(this);
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
)
66 bool HostStatusSender::OnSignalStrategyIncomingStanza(
67 const XmlElement
* stanza
) {
71 void HostStatusSender::SendOfflineStatus(HostExitCodes exit_code
) {
72 SendHostStatus(OFFLINE
, exit_code
);
75 void HostStatusSender::SendOnlineStatus() {
76 SendHostStatus(ONLINE
, kSuccessExitCode
);
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
)
86 << directory_bot_jid_
;
88 iq_sender_
->SendIq(buzz::STR_SET
,
90 CreateHostStatusMessage(status
, exit_code
),
91 IqSender::ReplyCallback());
93 HOST_LOG
<< "Cannot send host status to '"
95 << " ' because the state of the SignalStrategy is "
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
));
110 if (status
== OFFLINE
) {
111 host_status
->AddAttr(
112 QName(kChromotingXmlNamespace
, kExitCodeAttr
),
113 ExitCodeToString(exit_code
));
116 host_status
->AddElement(CreateSignature(status
, exit_code
).release());
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());
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();
134 scoped_ptr
<XmlElement
> HostStatusSender::CreateSignature(
135 HostStatus status
, HostExitCodes exit_code
) {
136 scoped_ptr
<XmlElement
> signature_tag(new XmlElement(
137 QName(kChromotingXmlNamespace
, kSignatureTag
)));
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
));
143 signature_tag
->AddAttr(
144 QName(kChromotingXmlNamespace
, kSignatureTimeAttr
), time_str
);
146 // Add a time stamp to the signature to prevent replay attacks.
147 std::string message
=
148 signal_strategy_
->GetLocalJid() +
152 HostStatusToString(status
);
154 if (status
== OFFLINE
)
155 message
+= std::string(" ") + ExitCodeToString(exit_code
);
157 std::string
signature(key_pair_
->SignMessage(message
));
158 signature_tag
->AddText(signature
);
160 return signature_tag
.Pass();
163 } // namespace remoting