Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / register_support_host_request.cc
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.
4
5 #include "remoting/host/register_support_host_request.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/time/time.h"
12 #include "remoting/base/constants.h"
13 #include "remoting/host/host_config.h"
14 #include "remoting/signaling/iq_sender.h"
15 #include "remoting/signaling/signal_strategy.h"
16 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
17 #include "third_party/webrtc/libjingle/xmpp/constants.h"
18
19 using buzz::QName;
20 using buzz::XmlElement;
21
22 namespace remoting {
23
24 namespace {
25 // Strings used in the request message we send to the bot.
26 const char kRegisterQueryTag[] = "register-support-host";
27 const char kPublicKeyTag[] = "public-key";
28 const char kSignatureTag[] = "signature";
29 const char kSignatureTimeAttr[] = "time";
30
31 // Strings used to parse responses received from the bot.
32 const char kRegisterQueryResultTag[] = "register-support-host-result";
33 const char kSupportIdTag[] = "support-id";
34 const char kSupportIdLifetimeTag[] = "support-id-lifetime";
35 }
36
37 RegisterSupportHostRequest::RegisterSupportHostRequest(
38     SignalStrategy* signal_strategy,
39     scoped_refptr<RsaKeyPair> key_pair,
40     const std::string& directory_bot_jid,
41     const RegisterCallback& callback)
42     : signal_strategy_(signal_strategy),
43       key_pair_(key_pair),
44       directory_bot_jid_(directory_bot_jid),
45       callback_(callback) {
46   DCHECK(signal_strategy_);
47   DCHECK(key_pair_.get());
48   signal_strategy_->AddListener(this);
49   iq_sender_.reset(new IqSender(signal_strategy_));
50 }
51
52 RegisterSupportHostRequest::~RegisterSupportHostRequest() {
53   if (signal_strategy_)
54     signal_strategy_->RemoveListener(this);
55 }
56
57 void RegisterSupportHostRequest::OnSignalStrategyStateChange(
58     SignalStrategy::State state) {
59   if (state == SignalStrategy::CONNECTED) {
60     DCHECK(!callback_.is_null());
61
62     request_ = iq_sender_->SendIq(
63         buzz::STR_SET, directory_bot_jid_,
64         CreateRegistrationRequest(signal_strategy_->GetLocalJid()).Pass(),
65         base::Bind(&RegisterSupportHostRequest::ProcessResponse,
66                    base::Unretained(this)));
67   } else if (state == SignalStrategy::DISCONNECTED) {
68     // We will reach here if signaling fails to connect.
69     CallCallback(false, std::string(), base::TimeDelta());
70   }
71 }
72
73 bool RegisterSupportHostRequest::OnSignalStrategyIncomingStanza(
74     const buzz::XmlElement* stanza) {
75   return false;
76 }
77
78 scoped_ptr<XmlElement> RegisterSupportHostRequest::CreateRegistrationRequest(
79     const std::string& jid) {
80   scoped_ptr<XmlElement> query(new XmlElement(
81       QName(kChromotingXmlNamespace, kRegisterQueryTag)));
82   XmlElement* public_key = new XmlElement(
83       QName(kChromotingXmlNamespace, kPublicKeyTag));
84   public_key->AddText(key_pair_->GetPublicKey());
85   query->AddElement(public_key);
86   query->AddElement(CreateSignature(jid).release());
87   return query.Pass();
88 }
89
90 scoped_ptr<XmlElement> RegisterSupportHostRequest::CreateSignature(
91     const std::string& jid) {
92   scoped_ptr<XmlElement> signature_tag(new XmlElement(
93       QName(kChromotingXmlNamespace, kSignatureTag)));
94
95   int64 time = static_cast<int64>(base::Time::Now().ToDoubleT());
96   std::string time_str(base::Int64ToString(time));
97   signature_tag->AddAttr(
98       QName(kChromotingXmlNamespace, kSignatureTimeAttr), time_str);
99
100   std::string message = jid + ' ' + time_str;
101   std::string signature(key_pair_->SignMessage(message));
102   signature_tag->AddText(signature);
103
104   return signature_tag.Pass();
105 }
106
107 bool RegisterSupportHostRequest::ParseResponse(const XmlElement* response,
108                                                std::string* support_id,
109                                                base::TimeDelta* lifetime) {
110   std::string type = response->Attr(buzz::QN_TYPE);
111   if (type == buzz::STR_ERROR) {
112     LOG(ERROR) << "Received error in response to heartbeat: "
113                << response->Str();
114     return false;
115   }
116
117   // This method must only be called for error or result stanzas.
118   if (type != buzz::STR_RESULT) {
119     LOG(ERROR) << "Received unexpect stanza of type \"" << type << "\"";
120     return false;
121   }
122
123   const XmlElement* result_element = response->FirstNamed(QName(
124       kChromotingXmlNamespace, kRegisterQueryResultTag));
125   if (!result_element) {
126     LOG(ERROR) << "<" << kRegisterQueryResultTag
127                << "> is missing in the host registration response: "
128                << response->Str();
129     return false;
130   }
131
132   const XmlElement* support_id_element =
133       result_element->FirstNamed(QName(kChromotingXmlNamespace, kSupportIdTag));
134   if (!support_id_element) {
135     LOG(ERROR) << "<" << kSupportIdTag
136                << "> is missing in the host registration response: "
137                << response->Str();
138     return false;
139   }
140
141   const XmlElement* lifetime_element =
142       result_element->FirstNamed(QName(kChromotingXmlNamespace,
143                                        kSupportIdLifetimeTag));
144   if (!lifetime_element) {
145     LOG(ERROR) << "<" << kSupportIdLifetimeTag
146                << "> is missing in the host registration response: "
147                << response->Str();
148     return false;
149   }
150
151   int lifetime_int;
152   if (!base::StringToInt(lifetime_element->BodyText().c_str(), &lifetime_int) ||
153       lifetime_int <= 0) {
154     LOG(ERROR) << "<" << kSupportIdLifetimeTag
155                << "> is malformed in the host registration response: "
156                << response->Str();
157     return false;
158   }
159
160   *support_id = support_id_element->BodyText();
161   *lifetime = base::TimeDelta::FromSeconds(lifetime_int);
162   return true;
163 }
164
165 void RegisterSupportHostRequest::ProcessResponse(IqRequest* request,
166                                                  const XmlElement* response) {
167   std::string support_id;
168   base::TimeDelta lifetime;
169   bool success = ParseResponse(response, &support_id, &lifetime);
170   CallCallback(success, support_id, lifetime);
171 }
172
173 void RegisterSupportHostRequest::CallCallback(
174     bool success, const std::string& support_id, base::TimeDelta lifetime) {
175   // Cleanup state before calling the callback.
176   request_.reset();
177   iq_sender_.reset();
178   signal_strategy_->RemoveListener(this);
179   signal_strategy_ = NULL;
180
181   RegisterCallback callback = callback_;
182   callback_.Reset();
183   callback.Run(success, support_id, lifetime);
184 }
185
186 }  // namespace remoting