1 // Copyright (c) 2012 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/register_support_host_request.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/time/time.h"
13 #include "remoting/base/constants.h"
14 #include "remoting/host/host_config.h"
15 #include "remoting/signaling/iq_sender.h"
16 #include "remoting/signaling/jid_util.h"
17 #include "remoting/signaling/signal_strategy.h"
18 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
19 #include "third_party/webrtc/libjingle/xmpp/constants.h"
22 using buzz::XmlElement
;
27 // Strings used in the request message we send to the bot.
28 const char kRegisterQueryTag
[] = "register-support-host";
29 const char kPublicKeyTag
[] = "public-key";
30 const char kSignatureTag
[] = "signature";
31 const char kSignatureTimeAttr
[] = "time";
33 // Strings used to parse responses received from the bot.
34 const char kRegisterQueryResultTag
[] = "register-support-host-result";
35 const char kSupportIdTag
[] = "support-id";
36 const char kSupportIdLifetimeTag
[] = "support-id-lifetime";
39 RegisterSupportHostRequest::RegisterSupportHostRequest(
40 SignalStrategy
* signal_strategy
,
41 scoped_refptr
<RsaKeyPair
> key_pair
,
42 const std::string
& directory_bot_jid
,
43 const RegisterCallback
& callback
)
44 : signal_strategy_(signal_strategy
),
46 directory_bot_jid_(directory_bot_jid
),
48 DCHECK(signal_strategy_
);
49 DCHECK(key_pair_
.get());
50 signal_strategy_
->AddListener(this);
51 iq_sender_
.reset(new IqSender(signal_strategy_
));
54 RegisterSupportHostRequest::~RegisterSupportHostRequest() {
56 signal_strategy_
->RemoveListener(this);
59 void RegisterSupportHostRequest::OnSignalStrategyStateChange(
60 SignalStrategy::State state
) {
61 if (state
== SignalStrategy::CONNECTED
) {
62 DCHECK(!callback_
.is_null());
64 request_
= iq_sender_
->SendIq(
65 buzz::STR_SET
, directory_bot_jid_
,
66 CreateRegistrationRequest(signal_strategy_
->GetLocalJid()).Pass(),
67 base::Bind(&RegisterSupportHostRequest::ProcessResponse
,
68 base::Unretained(this)));
69 } else if (state
== SignalStrategy::DISCONNECTED
) {
70 // We will reach here if signaling fails to connect.
71 std::string error_message
= "Signal strategy disconnected.";
72 LOG(ERROR
) << error_message
;
73 CallCallback(std::string(), base::TimeDelta(), error_message
);
77 bool RegisterSupportHostRequest::OnSignalStrategyIncomingStanza(
78 const buzz::XmlElement
* stanza
) {
82 scoped_ptr
<XmlElement
> RegisterSupportHostRequest::CreateRegistrationRequest(
83 const std::string
& jid
) {
84 scoped_ptr
<XmlElement
> query(new XmlElement(
85 QName(kChromotingXmlNamespace
, kRegisterQueryTag
)));
86 XmlElement
* public_key
= new XmlElement(
87 QName(kChromotingXmlNamespace
, kPublicKeyTag
));
88 public_key
->AddText(key_pair_
->GetPublicKey());
89 query
->AddElement(public_key
);
90 query
->AddElement(CreateSignature(jid
).release());
94 scoped_ptr
<XmlElement
> RegisterSupportHostRequest::CreateSignature(
95 const std::string
& jid
) {
96 scoped_ptr
<XmlElement
> signature_tag(new XmlElement(
97 QName(kChromotingXmlNamespace
, kSignatureTag
)));
99 int64 time
= static_cast<int64
>(base::Time::Now().ToDoubleT());
100 std::string
time_str(base::Int64ToString(time
));
101 signature_tag
->AddAttr(
102 QName(kChromotingXmlNamespace
, kSignatureTimeAttr
), time_str
);
104 std::string message
= NormalizeJid(jid
) + ' ' + time_str
;
105 std::string
signature(key_pair_
->SignMessage(message
));
106 signature_tag
->AddText(signature
);
108 return signature_tag
.Pass();
111 void RegisterSupportHostRequest::ParseResponse(const XmlElement
* response
,
112 std::string
* support_id
,
113 base::TimeDelta
* lifetime
,
114 std::string
* error_message
) {
115 std::ostringstream error
;
117 std::string type
= response
->Attr(buzz::QN_TYPE
);
118 if (type
== buzz::STR_ERROR
) {
119 error
<< "Received error in response to heartbeat: " << response
->Str();
120 *error_message
= error
.str();
121 LOG(ERROR
) << *error_message
;
125 // This method must only be called for error or result stanzas.
126 if (type
!= buzz::STR_RESULT
) {
127 error
<< "Received unexpect stanza of type \"" << type
<< "\"";
128 *error_message
= error
.str();
129 LOG(ERROR
) << *error_message
;
133 const XmlElement
* result_element
= response
->FirstNamed(QName(
134 kChromotingXmlNamespace
, kRegisterQueryResultTag
));
135 if (!result_element
) {
136 error
<< "<" << kRegisterQueryResultTag
137 << "> is missing in the host registration response: "
139 *error_message
= error
.str();
140 LOG(ERROR
) << *error_message
;
144 const XmlElement
* support_id_element
=
145 result_element
->FirstNamed(QName(kChromotingXmlNamespace
, kSupportIdTag
));
146 if (!support_id_element
) {
147 error
<< "<" << kSupportIdTag
148 << "> is missing in the host registration response: "
150 *error_message
= error
.str();
151 LOG(ERROR
) << *error_message
;
155 const XmlElement
* lifetime_element
=
156 result_element
->FirstNamed(QName(kChromotingXmlNamespace
,
157 kSupportIdLifetimeTag
));
158 if (!lifetime_element
) {
159 error
<< "<" << kSupportIdLifetimeTag
160 << "> is missing in the host registration response: "
162 *error_message
= error
.str();
163 LOG(ERROR
) << *error_message
;
168 if (!base::StringToInt(lifetime_element
->BodyText().c_str(), &lifetime_int
) ||
170 error
<< "<" << kSupportIdLifetimeTag
171 << "> is malformed in the host registration response: "
173 *error_message
= error
.str();
174 LOG(ERROR
) << *error_message
;
178 *support_id
= support_id_element
->BodyText();
179 *lifetime
= base::TimeDelta::FromSeconds(lifetime_int
);
183 void RegisterSupportHostRequest::ProcessResponse(IqRequest
* request
,
184 const XmlElement
* response
) {
185 std::string support_id
;
186 base::TimeDelta lifetime
;
187 std::string error_message
;
188 ParseResponse(response
, &support_id
, &lifetime
, &error_message
);
189 CallCallback(support_id
, lifetime
, error_message
);
192 void RegisterSupportHostRequest::CallCallback(
193 const std::string
& support_id
,
194 base::TimeDelta lifetime
,
195 const std::string
& error_message
) {
196 // Cleanup state before calling the callback.
199 signal_strategy_
->RemoveListener(this);
200 signal_strategy_
= nullptr;
202 base::ResetAndReturn(&callback_
).Run(support_id
, lifetime
, error_message
);
205 } // namespace remoting