Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / remoting / signaling / iq_sender.cc
blob9e5434019cac6500be6685ce9cb6e06c8d6a8844
1 // Copyright 2014 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/signaling/iq_sender.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.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"
21 namespace remoting {
23 // static
24 scoped_ptr<buzz::XmlElement> IqSender::MakeIqStanza(
25 const std::string& type,
26 const std::string& addressee,
27 scoped_ptr<buzz::XmlElement> iq_body) {
28 scoped_ptr<buzz::XmlElement> stanza(new buzz::XmlElement(buzz::QN_IQ));
29 stanza->AddAttr(buzz::QN_TYPE, type);
30 if (!addressee.empty())
31 stanza->AddAttr(buzz::QN_TO, addressee);
32 stanza->AddElement(iq_body.release());
33 return stanza.Pass();
36 IqSender::IqSender(SignalStrategy* signal_strategy)
37 : signal_strategy_(signal_strategy) {
38 signal_strategy_->AddListener(this);
41 IqSender::~IqSender() {
42 signal_strategy_->RemoveListener(this);
45 scoped_ptr<IqRequest> IqSender::SendIq(scoped_ptr<buzz::XmlElement> stanza,
46 const ReplyCallback& callback) {
47 std::string addressee = stanza->Attr(buzz::QN_TO);
48 std::string id = signal_strategy_->GetNextId();
49 stanza->AddAttr(buzz::QN_ID, id);
50 if (!signal_strategy_->SendStanza(stanza.Pass())) {
51 return nullptr;
53 DCHECK(requests_.find(id) == requests_.end());
54 scoped_ptr<IqRequest> request(new IqRequest(this, callback, addressee));
55 if (!callback.is_null())
56 requests_[id] = request.get();
57 return request.Pass();
60 scoped_ptr<IqRequest> IqSender::SendIq(const std::string& type,
61 const std::string& addressee,
62 scoped_ptr<buzz::XmlElement> iq_body,
63 const ReplyCallback& callback) {
64 return SendIq(MakeIqStanza(type, addressee, iq_body.Pass()), callback);
67 void IqSender::RemoveRequest(IqRequest* request) {
68 IqRequestMap::iterator it = requests_.begin();
69 while (it != requests_.end()) {
70 IqRequestMap::iterator cur = it;
71 ++it;
72 if (cur->second == request) {
73 requests_.erase(cur);
74 break;
79 void IqSender::OnSignalStrategyStateChange(SignalStrategy::State state) {
82 bool IqSender::OnSignalStrategyIncomingStanza(const buzz::XmlElement* stanza) {
83 if (stanza->Name() != buzz::QN_IQ) {
84 LOG(WARNING) << "Received unexpected non-IQ packet " << stanza->Str();
85 return false;
88 const std::string& type = stanza->Attr(buzz::QN_TYPE);
89 if (type.empty()) {
90 LOG(WARNING) << "IQ packet missing type " << stanza->Str();
91 return false;
94 if (type != "result" && type != "error") {
95 return false;
98 const std::string& id = stanza->Attr(buzz::QN_ID);
99 if (id.empty()) {
100 LOG(WARNING) << "IQ packet missing id " << stanza->Str();
101 return false;
104 std::string from = stanza->Attr(buzz::QN_FROM);
106 IqRequestMap::iterator it = requests_.find(id);
107 if (it == requests_.end()) {
108 return false;
111 IqRequest* request = it->second;
113 if (NormalizeJid(request->addressee_) != NormalizeJid(from)) {
114 LOG(ERROR) << "Received IQ response from an invalid JID. Ignoring it."
115 << " Message received from: " << from
116 << " Original JID: " << request->addressee_;
117 return false;
120 requests_.erase(it);
121 request->OnResponse(stanza);
123 return true;
126 IqRequest::IqRequest(IqSender* sender, const IqSender::ReplyCallback& callback,
127 const std::string& addressee)
128 : sender_(sender),
129 callback_(callback),
130 addressee_(addressee) {
133 IqRequest::~IqRequest() {
134 sender_->RemoveRequest(this);
137 void IqRequest::SetTimeout(base::TimeDelta timeout) {
138 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
139 FROM_HERE, base::Bind(&IqRequest::OnTimeout, AsWeakPtr()), timeout);
142 void IqRequest::CallCallback(const buzz::XmlElement* stanza) {
143 if (!callback_.is_null())
144 base::ResetAndReturn(&callback_).Run(this, stanza);
147 void IqRequest::OnTimeout() {
148 CallCallback(nullptr);
151 void IqRequest::OnResponse(const buzz::XmlElement* stanza) {
152 // It's unsafe to delete signal strategy here, and the callback may
153 // want to do that, so we post task to invoke the callback later.
154 scoped_ptr<buzz::XmlElement> stanza_copy(new buzz::XmlElement(*stanza));
155 base::ThreadTaskRunnerHandle::Get()->PostTask(
156 FROM_HERE, base::Bind(&IqRequest::DeliverResponse, AsWeakPtr(),
157 base::Passed(&stanza_copy)));
160 void IqRequest::DeliverResponse(scoped_ptr<buzz::XmlElement> stanza) {
161 CallCallback(stanza.get());
164 } // namespace remoting