- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / host / host_status_sender.cc
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/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/stringize_macros.h"
10 #include "base/time/time.h"
11 #include "remoting/base/constants.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     LOG(INFO) << "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     LOG(INFO) << "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